搜索
首页web前端js教程4个开发React应用的实用技巧

4个开发React应用的实用技巧

Nov 26, 2019 pm 06:08 PM
javascriptnode.jsreact.jstypescriptvue.js

4个开发React应用的实用技巧

【相关专题推荐:react面试题(2020)】

背景

Hooks 自推出以来就很火, 它改变了我们编写React 代码的方式, 有助于我们写更简洁的代码。

今天这边文章不是说Hooks的,Hooks之外, 还有很多实用的技巧可以帮助我们编写简洁清晰的代码。

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

正文

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

举个简单的例子:

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

const MyComponent = 'p'

function App() {
  return (
    <>
      <MyComponent>
        <h3>I am inside a {'<p />'} element</h3>
      </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 component="p" name="KK" age={18} email="xxx@gmail.com">
    </>
  )
}

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

function Dashboard({ children }) {
  return (
    <p style={{ padding: &#39;25px 12px&#39; }}>
      {children}
    </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 = 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

1.png

基于以上原因,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 />
</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 style={style} {...this.props} />
    }
  }
  
  return WithBorder
}

function MyComponent({ style, ...rest }) {
  return (
    <p style={style} {...rest}>
        <h2>
          This is my component and I am expecting some styles.
        </h2>
    </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: &#39;100%&#39; }} onMouseMove={this.handleMouseMove}>
        <p>The current mouse position is ({this.state.x}, {this.state.y})</p>
      </p>
    );
  }
}

class MouseTracker extends React.Component {
  render() {
    return (
      <>
        <h1>移动鼠标!</h1>
        <Mouse />
      </>
    );
  }
}

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

现在的问题是:

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

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

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

我们或许会使用

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: &#39;absolute&#39;, left: mouse.x, top: mouse.y }} />
    );
  }
}</p>
<p>这个需求如此简单,你可能就直接修改Mouse组件了:</p>
<pre class="brush:php;toolbar:false">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: &#39;100%&#39; }} onMouseMove={this.handleMouseMove}>
        <Cat mouse={this.state} />
      </p>
    );
  }
}

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

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

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

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

这也是 render prop 的来历:

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

修改一下上面的代码:

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: &#39;absolute&#39;, 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: &#39;100%&#39; }} onMouseMove={this.handleMouseMove}>
        {this.props.render(this.state)}
      </p>
    );
  }
}

class MouseTracker extends React.Component {
  render() {
    return (
      <p>
        <h1>移动鼠标!</h1>
        <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} />
        )}/>
      </>
    );
  }
}

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

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

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

  render() {
    return (
      <p>
        <h1>Move the mouse around!</h1>
        <Mouse render={this.renderTheCat} />
      </p>
    );
  }
}

5.组件性能

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

总结

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

推荐阅读:React在线手册

以上是4个开发React应用的实用技巧的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:segmentfault。如有侵权,请联系admin@php.cn删除
Python vs. JavaScript:社区,图书馆和资源Python vs. JavaScript:社区,图书馆和资源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C到JavaScript:所有工作方式从C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript引擎:比较实施JavaScript引擎:比较实施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)