>  기사  >  웹 프론트엔드  >  React 앱 개발을 위한 4가지 실용적인 팁

React 앱 개발을 위한 4가지 실용적인 팁

青灯夜游
青灯夜游앞으로
2019-11-26 18:08:034325검색

React 앱 개발을 위한 4가지 실용적인 팁

【관련 주제 추천: react 인터뷰 질문 (2020)】

Background

Hooks는 출시 이후 큰 인기를 끌었습니다. 보다 간결한 코드를 작성하는 데 도움이 됩니다.

오늘의 기사는 Hooks에 관한 것이 아닙니다. Hooks 외에도 간결하고 명확한 코드를 작성하는 데 도움이 되는 많은 실용적인 기술이 있습니다. 简洁清晰的代码。

今天我就整理了几个使用的技巧,其中有些也是我在公司项目中实践的,现在整理出来分享给大家, 希望对大家有所启发

正文

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

举个简单的例子:

// 我们可以通过把一个字符串'p' 赋值给一个变量, 就像:
import React from 'react'

const MyComponent = 'p'

function App() {
  return (
    
      <mycomponent>
        <h3>I am inside a {'</h3>
<p></p>'} element
      </mycomponent>
    >
  )
}

React 内部会调用 React.createElement, 使用这个字符串来生成这个元素。

另外, 你也可以显式的定义component 来决定渲染的内容, 比如:

// 定义一个MyComponent
function MyComponent({ component: Component = 'p', name, age, email }) {
  
  return (
    <component>
      <h1>Hi {name} </h1>
      
        <h6>You are {age} years old</h6>
        <small>Your email is {email}</small>
      >
    </component>
  )
}

适用方式:

function App() {
  return (
    
      <mycomponent>
    >
  )
}</mycomponent>

这种方式, 你也可以传入一个自定义的组件, 比如:

function Dashboard({ children }) {
  return (
    

      {children}     

  ) } function App() {   return (            <mycomponent>     >   ) }</mycomponent>

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

举个现实的例子:

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

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></packcomponent>
  )
}

PackEditor = withTranslate(PackEditor)
PackEditor.check = check

export 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 앱 개발을 위한 4가지 실용적인 팁

基于以上原因,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 <h1>Something went wrong.</h1>
    }
    return this.props.children
  }
}

使用方式:

<errorboundary>
  <mywidget></mywidget>
</errorboundary>

Live Demo By Dan Abramov:

https://codepen.io/gaearon/pen/wqvxGa?editors=0010

3.高阶组件

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

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

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

import React from 'react'

// Higher order component
const withBorder = (Component, customStyle) => {
  class WithBorder extends React.Component {
    render() {
      const style = {
        border: this.props.customStyle ? this.props.customStyle.border : '3px solid teal'
      }
      return <component></component>
    }
  }
  
  return WithBorder
}

function MyComponent({ style, ...rest }) {
  return (
    <p>
        </p><h2>
          This is my component and I am expecting some styles.
        </h2>
    
  )
}

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> { // 注入翻译方法
          if (!id) { return '' }
          return intl.formatMessage(
            typeof id === 'string' ? { id } : id,
            values
          )
        }}
        {...others}
      />
    )
  ), [])

  IntlComponent.displayName = `withTranslate(${BaseComponent.displayName || 'BaseComponent'})`
  
  return (
    <provider>
      <intl>
        <intlcomponent></intlcomponent>
      </intl>
    </provider>
  )
}

export default withTranslate</basecomponent>

用法很灵过:

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

十分的方便。

4. Render props

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

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

오늘 저는 몇 가지 기술을 정리했습니다. 그중 일부는 회사 프로젝트에서 연습하여 여러분과 공유할 수 있기를 바랍니다. >.

Text

1. 문자열을 사용하여 React 요소를 정의하세요

🎜🎜🎜간단한 예: 🎜
class Mouse extends React.Component {
  state = { x: 0, y: 0 };

  handleMouseMove = (event) => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      <p>
        </p><p>The current mouse position is ({this.state.x}, {this.state.y})</p>
      
    );
  }
}

class MouseTracker extends React.Component {
  render() {
    return (
      
        <h1>移动鼠标!</h1>
        <mouse></mouse>
      >
    );
  }
}
🎜React는 내부적으로 React.createElement는 이 문자열을 사용하여 이 요소를 생성합니다. 🎜🎜또한 다음과 같이 구성 요소를 명시적으로 정의하여 렌더링된 콘텐츠를 결정할 수도 있습니다. 🎜
class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img  alt="React 앱 개발을 위한 4가지 실용적인 팁" >
    );
  }
}
🎜적용 가능한 방법: 🎜
class Mouse extends React.Component {
  state = { x: 0, y: 0 };

  handleMouseMove = (event) => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      <p>
        <cat></cat>
      </p>
    );
  }
}
🎜이런 방식으로 사용자 정의 구성 요소를 전달할 수도 있습니다. 예: 🎜
class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img  alt="React 앱 개발을 위한 4가지 실용적인 팁" >
    );
  }
}

class Mouse extends React.Component {
  state = { x: 0, y: 0 };

  handleMouseMove = (event) => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      

        {this.props.render(this.state)}       

    );   } } class MouseTracker extends React.Component {   render() {     return (       

        

移动鼠标!

         (                    )}/>            );   } }
🎜 를 처리하는 유사한 요소나 구성 요소를 발견하면 이 사용자 정의 방식으로 이를 추상화하고 코드를 단순화할 수 있습니다. 🎜🎜실제 예를 들어보겠습니다. 🎜🎜예를 들어, 우리는 이제 개별적으로 또는 일괄적으로 수행할 수 있는 상품 포장에 대한 수요를 만들고 있습니다. 우리는 공통점을 기반으로 맞춤형 구성 요소를 작성할 수 있습니다. 🎜
function withMouse(Component) {
  return class extends React.Component {
    render() {
      return (
        <mouse> (
          <component></component>
        )}/>
      );
    }
  }
}</mouse>
🎜여기서 다양한 비즈니스 모듈에서 유연하게 사용할 수 있어 매우 편리합니다. 🎜🎜🎜2. 오류 경계 정의🎜🎜🎜🎜Javascript에서는 모두 try/catch를 사용하여 잡기. 예: 🎜
class Mouse extends React.PureComponent {
  // 与上面相同的代码......
}

class MouseTracker extends React.Component {
  render() {
    return (
      
        <mouse> ( // 这是不好的! 每个渲染的 `render` prop的值将会是不同的。
          <cat></cat>
        )}/>
      >
    );
  }
}</mouse>
🎜 이렇게 하면 오류가 발생하더라도 애플리케이션이 흰색 화면과 함께 충돌하지 않습니다. 🎜🎜React도 최종 분석에서는 Javascript이고 본질적으로는 차이가 없으므로 try/catch를 같은 방식으로 사용해도 문제가 없습니다. 🎜🎜그러나 React 구현 메커니즘으로 인해 구성 요소 내부에서 발생하는 Javascript 오류는 내부 상태를 파괴하고 렌더링 시 오류가 생성됩니다: 🎜🎜https://github.com/facebook/react/issues/4026🎜🎜🎜🎜위 내용을 바탕으로 이유로 React 팀은 실제로 React 구성 요소인 Error Boundaries를 도입했습니다:🎜🎜https://reactjs.org/docs/error-boundaries.html🎜🎜Error Boundaries . 컴포넌트를 사용하여 포착한 오류 메시지를 처리할 수 있습니다. 🎜🎜컴포넌트 트리가 무너지면 사용자 정의된 UI도 대체적으로 표시될 수 있습니다. 🎜🎜React에서 제공하는 공식 예제를 살펴보세요.
https://reactjs.org/docs/error-boundaries.html#introducing-error-boundaries🎜
class MouseTracker extends React.Component {
  renderTheCat(mouse) {
    return <cat></cat>;
  }

  render() {
    return (
      <p>
        </p><h1>Move the mouse around!</h1>
        <mouse></mouse>
      
    );
  }
}
🎜사용 방법: 🎜rrreee🎜Live Demo By Dan Abramov:🎜 🎜https://codepen.io/gaearon/pen/wqvxGa?editors=0010🎜🎜🎜3. 고급 구성요소🎜🎜🎜🎜일반인의 관점에서 , 소위 상위 수준 구성 요소 구성 요소는 구성 요소를 넣고 일부 속성이나 작업을 추가한 다음 버리는 것을 의미합니다. 🎜🎜일반적으로 말하면 공통점이 있는 일부 구성 요소를 고차 구성 요소로 추상화한 다음 다른 모듈에서 재사용할 수 있습니다.> 🎜🎜예를 들어, 우리 시스템에는 여러 곳에서 사용되는 테두리를 추가해야 하는 버튼 유형이 있습니다. 🎜rrreee🎜MyComponent 구성 요소는 다음과 같이 장식됩니다. withBorder에는 있습니다. 나중에 테두리 기능을 통합하고 싶다면 이 중간 레이어에 통합하면 매우 편리합니다. 🎜🎜내 프로젝트에서는 몇 가지 고차원 구성요소도 사용합니다. 구체적인 예를 들면 다음과 같습니다. 🎜rrreee🎜저희 PackEditor는 어떤 기능이 추가되었나요? 🎜🎜이름에서 알 수 있듯이 withTranslate는 번역 기능을 추가합니다. 이 구성 요소를 구현하는 방법을 보여 드리겠습니다. 🎜rrreee🎜사용이 매우 유연합니다. 🎜rrreee🎜매우 편리합니다. 🎜🎜🎜4.Render props🎜🎜🎜🎜Rrender prop은 React 컴포넌트 사이에 사용되는 함수를 값으로 가지는 prop을 말합니다. 코드를 공유하는 간단한 기술은 구성 요소 간의 논리적 재사용 문제인 HOC와 유사합니다. 🎜🎜더 구체적으로, Render prop은 렌더링할 콘텐츠를 구성 요소에 알려주는 데 사용되는 함수입니다. 🎜🎜아래의 간단한 예를 살펴보십시오. 🎜🎜다음 구성 요소는 웹 애플리케이션에서 마우스 위치를 추적합니다. 🎜rrreee🎜커서가 화면을 가로질러 움직일 때 구성 요소는 해당 (x,y) 좌표를 표시합니다. 🎜🎜이제 질문은: 🎜🎜이 동작을 다른 구성 요소에서 어떻게 재사용합니까? 🎜

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

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

我们或许会使用

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img  alt="React 앱 개발을 위한 4가지 실용적인 팁" >
    );
  }
}

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

class Mouse extends React.Component {
  state = { x: 0, y: 0 };

  handleMouseMove = (event) => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      <p>
        <cat></cat>
      </p>
    );
  }
}

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

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

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

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

这也是 render prop 的来历:

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

修改一下上面的代码:

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img  alt="React 앱 개발을 위한 4가지 실용적인 팁" >
    );
  }
}

class Mouse extends React.Component {
  state = { x: 0, y: 0 };

  handleMouseMove = (event) => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      

        {this.props.render(this.state)}       

    );   } } class MouseTracker extends React.Component {   render() {     return (       

        

移动鼠标!

         (                    )}/>       

    );   } }

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

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

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

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

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

function withMouse(Component) {
  return class extends React.Component {
    render() {
      return (
        <mouse> (
          <component></component>
        )}/>
      );
    }
  }
}</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` prop的值将会是不同的。
          <cat></cat>
        )}/>
      >
    );
  }
}</mouse>

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

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

class MouseTracker extends React.Component {
  renderTheCat(mouse) {
    return <cat></cat>;
  }

  render() {
    return (
      <p>
        </p><h1>Move the mouse around!</h1>
        <mouse></mouse>
      
    );
  }
}

5.组件性能

性能优化是永恒的主题, 这里不一一细说, 提供积分资源供你参考:

总结

以上几点都是我们经常要使用的技巧, 简单实用, 分享给大家, 希望能给大家带来一些帮助或启发,谢谢。

推荐阅读:React在线手册

위 내용은 React 앱 개발을 위한 4가지 실용적인 팁의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제