开发React应用的实用技巧有哪些

技术开发React应用的实用技巧有哪些这篇文章将为大家详细讲解有关开发React应用的实用技巧有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。背景Hooks 自推出以

本文将详细解释开发React应用程序的实用技巧。文章内容质量较高,边肖将分享给大家参考。希望你看完这篇文章后有所了解。

背景

自推出以来,Hooks一直非常受欢迎。它改变了我们编写React代码的方式,帮助我们编写更简洁的代码。

正文

1. 使用字符串来定义一个React元素

举个简单的例子:

//我们可以将一个字符串“p”赋给一个变量,就像:import reactivitfrom“react”const my component=“p”functionapp(){ return(my component H4 iamsinidia { ' p/' } element/H4/my component/)} react将在内部调用React.createElement并使用此字符串来

此外,您还可以显式定义组件来确定呈现的内容,例如:

//定义my component function my component({ component 3360 component=' p ',姓名,年龄,电子邮件}){ return(component H2 hi { name }/H2 H7 your are { age }岁/H7 small your email { email }/small//component)}:

function app(){ return(my component component=' p ' name=' kk ' age={ 18 } email=' XXX @ Gmail.com '/)}通过这种方式,还可以传入自定义组件,例如:

function dashboard({ children }){ return(PS tyle={ { padd : ' 25px12 px ' } } { c

hildren}    </p>  )}function App() {  return (    <>      <MyComponent component={Dashboard} name="KK" age={18} email="xxx@gmail.com">    </>  )}

如果你遇到处理一类相似的元素或者组件,可以通过这种自定义的方式抽象出来,简化你的代码。

举个现实的例子:

比如我们现在要做一个货物打包的需求, 可以单个打, 也可以批量打, 针对共同点可以写自定义组件:

import React from 'react'import withTranslate from '@components/withTranslate'import PackComponent from './PackComponent'import usePack, { check } from './usePack'let PackEditor = (props) => {  const packRes = usePack(props)  return (    <PackComponent      {...packRes}    />  )}PackEditor = withTranslate(PackEditor)PackEditor.check = checkexport default PackEditor

这样在不同的业务模块中, 就可以灵活的使用了, 非常方便。

2. 定义错误边界

在Javascript里,我们都是使用 try/catch 来捕捉可能发生的异常,在catch中处理错误。 比如:

function getFromLocalStorage(key, value) {  try {    const data = window.localStorage.get(key)    return JSON.parse(data)  } catch (error) {    console.error  }}

这样, 即便发生了错误, 我们的应用也不至于崩溃白屏。

React 归根结底也是Javascript,本质上没什么不同, 所以同样的使用try/catch  也没有问题。

然而, 由于React 实现机制的原因, 发生在组件内部的Javascript 错误会破坏内部状态, render会产生错误:

https://github.com/facebook/react/issues/4026

基于以上原因,React 团队引入了Error Boundaries:

https://reactjs.org/docs/error-boundaries.html

Error boundaries, 其实就是React组件, 你可以用找个组件来处理它捕捉到的任何错误信息。

当组件树崩溃的时候,也可以显示你自定义的UI,作为回退。

看 React 官方提供的例子:https://reactjs.org/docs/error-boundaries.html#introducing-error-boundaries

class ErrorBoundary extends React.Component {  constructor(props) {    super(props)    this.state = { hasError: false }  }    static getDerivedStateFromError(error) {    // Update state so the next render will show the fallback UI.    return { hasError: true }  }    componentDidCatch(error, errorInfo) {    // You can also log the error to an error reporting service    logErrorToMyService(error, errorInfo)  }    render() {    if (this.state.hasError) {      // You can render any custom fallback UI      return <h2>Something went wrong.</h2>    }    return this.props.children  }}

使用方式:

<ErrorBoundary>  <MyWidget /></ErrorBoundary>

Live Demo By Dan Abramov:

3.高阶组件

通俗点讲, 所谓高阶组件就是, 你丢一个组件进去, 增加一些属性或操作, 再丢出来。

一般来说, 你可以把一些具备共同点的组件抽象成一个高阶组件, 然后再不同的模块中复用

比如, 我们的系统中, 有一类按钮要加个border, 很多地方都要用到, 我们把它抽象出来:

import React from 'react'// Higher order componentconst withBorder = (Component, customStyle) => {  class WithBorder extends React.Component {    render() {      const style = {        border: this.props.customStyle ? this.props.customStyle.border : '3px solid teal'      }      return <Component style={style} {...this.props} />    }  }    return WithBorder}function MyComponent({ style, ...rest }) {  return (    <p style={style} {...rest}>        <h3>          This is my component and I am expecting some styles.        </h3>    </p>  )}export default withBorder(MyComponent, { border: '4px solid teal' })

经过withBorder装饰的MyComponent组件, 就具备了统一border这项功能, 后面如果如果要做修改, 就可以在这个中间层统一处理, 非常方便。

在我的项目里, 也用了一些高阶组件, 举个具体的例子:

PackEditor = withTranslate(PackEditor)

我们的这个 PackEditor 就是一个增强过的组件, 增加了什么功能呢?

正如名字表述的, withTranslate, 增加了一个翻译功能, 下面也给大家看看这个组件是怎么实现的:

import React from 'react'import { Provider } from 'react-redux'import { injectIntl } from 'react-intl'import { store } from '@redux/store'import { Intl } from './Locale'const withTranslate = BaseComponent => (props) => {  // avoid create a new component on re-render  const IntlComponent = React.useMemo(() => injectIntl(    ({ intl, ...others }) => (      <BaseComponent        intl={intl}        translate={(id, values = {}) => { // 注入翻译方法          if (!id) { return '' }          return intl.formatMessage(            typeof id === 'string' ? { id } : id,            values          )        }}        {...others}      />    )  ), [])  IntlComponent.displayName = `withTranslate(${BaseComponent.displayName || 'BaseComponent'})`    return (    <Provider store={store}>      <Intl>        <IntlComponent          {...props}        />      </Intl>    </Provider>  )}export default withTranslate

用法很灵过:

const Editor = withTranslate(({  // ...  translate,}) => {  // ...   return (     <>      {translate('xxx')}}     </>   )})

十分的方便。

4. Render props

Rrender prop 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术, 和 HOC 类似, 都是组件间的逻辑复用问题

更具体地说,Render prop 是一个用于告知组件需要渲染什么内容的函数。

下面看一下简单的例子:

以下组件跟踪 Web 应用程序中的鼠标位置:

class Mouse extends React.Component {  state = { x: 0, y: 0 };  handleMouseMove = (event) => {    this.setState({      x: event.clientX,      y: event.clientY    });  }  render() {    return (      <p style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>        <p>The current mouse position is ({this.state.x}, {this.state.y})</p>      </p>    );  }}class MouseTracker extends React.Component {  render() {    return (      <>        <h2>移动鼠标!</h2>        <Mouse />      </>    );  }}

当光标在屏幕上移动时,组件显示其(x,y)坐标。

现在的问题是:

我们如何在另一个组件中复用这个行为?

换个说法,若另一个组件需要知道鼠标位置,我们能否封装这一行为,以便轻松地与其他组件共享它 ??

假设产品想要这样一个功能: 在屏幕上呈现一张在屏幕上追逐鼠标的猫的图片。

我们或许会使用 <Cat mouse={{ x, y }} prop 来告诉组件鼠标的坐标以让它知道图片应该在屏幕哪个位置。

class Cat extends React.Component {  render() {    const mouse = this.props.mouse;    return (      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />    );  }}

这个需求如此简单,你可能就直接修改Mouse组件了:

class Mouse extends React.Component {  state = { x: 0, y: 0 };  handleMouseMove = (event) => {    this.setState({      x: event.clientX,      y: event.clientY    });  }  render() {    return (      <p style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>        <Cat mouse={this.state} />      </p>    );  }}

巴适~ 简单粗暴, 一分钟完成任务。

可是,如果下次产品再要想加条狗呢

以上的例子,虽然可以完成了猫追鼠标的需求,还没有达到以可复用的方式真正封装行为的目标。

当我们想要鼠标位置用于不同的用例时,我们必须创建一个新的组件,专门为该用例呈现一些东西.

这也是 render prop 的来历:

我们可以提供一个带有函数 prop 的 <Mouse> 组件,它能够动态决定什么需要渲染的,而不是将 <Cat> 硬编码到 <Mouse> 组件里.

修改一下上面的代码:

class Cat extends React.Component {  render() {    const mouse = this.props.mouse;    return (      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />    );  }}class Mouse extends React.Component {  state = { x: 0, y: 0 };  handleMouseMove = (event) => {    this.setState({      x: event.clientX,      y: event.clientY    });  }  render() {    return (      <p style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>        {this.props.render(this.state)}      </p>    );  }}class MouseTracker extends React.Component {  render() {    return (      <p>        <h2>移动鼠标!</h2>        <Mouse render={mouse => (          <Cat mouse={mouse} />        )}/>      </p>    );  }}

提供了一个render 方法,让动态决定什么需要渲染。

事实上,render prop 是因为模式才被称为 render prop ,不一定要用名为 render 的 prop 来使用这种模式。

任何被用于告知组件需要渲染什么内容的函数 prop, 在技术上都可以被称为 "render prop".

另外,关于 render prop 一个有趣的事情是你可以使用带有 render prop 的常规组件来实现大多数高阶组件 (HOC)。

例如,如果你更喜欢使用 withMouse HOC 而不是 <Mouse> 组件,你可以使用带有 render prop 的常规 <Mouse> 轻松创建一个:

function withMouse(Component) {  return class extends React.Component {    render() {      return (        <Mouse render={mouse => (          <Component {...this.props} mouse={mouse} />        )}/>      );    }  }}

也是非常的简洁清晰。

有一点需要注意的是, 如果你在定义的render函数里创建函数, 使用 render prop 会抵消使用 React.PureComponent 带来的优势。

因为浅比较 props 的时候总会得到 false,并且在这种情况下每一个 render 对于 render prop 将会生成一个新的值

class Mouse extends React.PureComponent {  // 与上面相同的代码......}class MouseTracker extends React.Component {  render() {    return (      <>        <Mouse render={mouse => ( // 这是不好的! 每个渲染的 `render` prop的值将会是不同的。          <Cat mouse={mouse} />        )}/>      </>    );  }}

在这样例子中,每次 <MouseTracker> 渲染,它会生成一个新的函数作为 <Mouse render> 的 prop,因而在同时也抵消了继承自 React.PureComponent 的 <Mouse> 组件的效果.

为了绕过这一问题,有时你可以定义一个 prop 作为实例方法,类似这样:

class MouseTracker extends React.Component {  renderTheCat(mouse) {    return <Cat mouse={mouse} />;  }  render() {    return (      <p>        <h2>Move the mouse around!</h2>        <Mouse render={this.renderTheCat} />      </p>    );  }}

关于开发React应用的实用技巧有哪些就分享到这里了,希望

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/117461.html

(0)

相关推荐

  • MySQL 5.7中PREPARE、EXECUTE、DEALLOCATE语句怎么用

    技术MySQL 5.7中PREPARE、EXECUTE、DEALLOCATE语句怎么用小编给大家分享一下MySQL 5.7中PREPARE、EXECUTE、DEALLOCATE语句怎么用,相信大部分人都还不怎么了解,因此

    攻略 2021年10月30日
  • let、const、var的区别

    技术let、const、var的区别 let、const、var的区别1、var是ES5提出的,let和const是ES6提出的。
    2、const声明的是常量,必须赋值  1)一旦声明必须赋值,不能使用

    礼包 2021年12月5日
  • 脚背穴位,肾囊肿吃什么中药比较管用

    技术脚背穴位,肾囊肿吃什么中药比较管用我是医者良言脚背穴位,是一名住院医师,专为普及医学知识造福人类健康,若想了解更多,请关注我,有疑问可留言,必回应!肾囊肿吃什么中药比较好?其实肾囊肿的发病率不低,很多人是在做肝胆胰脾

    生活 2021年10月23日
  • 春卷的馅料有哪些,粽子有哪些馅料粽子馅料种类

    技术春卷的馅料有哪些,粽子有哪些馅料粽子馅料种类粽子的口味很多春卷的馅料有哪些,馅料相当丰富,除了传统的鲜肉粽、豆沙粽、蛋黄肉粽、红枣粽、板栗粽、莲子粽外,还有百果粽、紫薯粽、桂花飘香粽、鲍汁牛柳粽、干贝鲜肉粽,等等。凡

    生活 2021年10月31日
  • JS如何实现拖拽进度条改变元素透明度

    技术JS如何实现拖拽进度条改变元素透明度JS如何实现拖拽进度条改变元素透明度,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。今天要分享的是运用原生JS拖拽

    攻略 2021年10月20日
  • 一筹莫展什么意思,一筹莫展的筹是什么意思

    技术一筹莫展什么意思,一筹莫展的筹是什么意思◎ 一筹莫展 yīchóu-mòzhǎn筹:计策。展:施展。一点计策也想不出;一点儿办法也没有《宋史·蔡幼学传》:“多士盈庭而一筹不吐。”后以“一筹莫展”比喻一点办法也没有。

    生活 2021年10月29日