<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          干貨!幾個灰常實用的React實踐技巧(收藏)

          共 7834字,需瀏覽 16分鐘

           ·

          2020-10-29 12:23

          背景


          Hooks 自推出以來就很火, 它改變了我們編寫React 代碼的方式, 有助于我們寫更簡潔的代碼。

          今天這邊文章不是說Hooks的,Hooks之外, 還有很多實用的技巧可以幫助我們便攜簡潔實用的代碼。

          今天我就整理了8個使用的技巧,其中有些也是我在公司項目中實踐的,現(xiàn)在整理出來分享給大家, 希望對大家有所啟發(fā)。

          正文





          1. 使用字符串來定義一個React元素

          舉個簡單的例子:

          // 我們可以通過把一個字符串'div' 賦值給一個變量, 就像:
          import React from 'react'

          const MyComponent = 'div'

          function App() {
          return (
          <>
          <MyComponent>
          <h3>I am inside a {'<div />'} elementh3>

          MyComponent>

          )
          }

          React 內(nèi)部會調用 React.createElement, 使用這個字符串來生成這個元素。

          另外, 你也可以顯式的定義component 來決定渲染的內(nèi)容, 比如:

          // 定義一個MyComponent
          function MyComponent({ component: Component = 'div', name, age, email }) {

          return (
          <Component>
          <h1>Hi {name} h1>

          <>
          <h6>You are {age} years oldh6>
          <small>Your email is {email}small>

          Component>
          )
          }

          適用方式:

          function App() {
          return (
          <>


          )
          }

          這種方式, 你也可以傳入一個自定義的組件, 比如:

          function Dashboard({ children }) {
          return (
          <div style={{ padding: '25px 12px' }}>
          {children}
          div>

          )
          }

          function App() {
          return (
          <>


          )
          }

          如果你遇到處理一類相似的元素或者組件,可以通過這種自定義的方式抽象出來,簡化你的代碼。

          舉個現(xiàn)實的例子:

          比如我們現(xiàn)在要做一個貨物打包的需求, 可以單個打, 也可以批量打, 針對共同點可以寫自定義組件:

          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

          這樣在不同的業(yè)務模塊中, 就可以靈活的使用了, 非常方便。

          2. 定義錯誤邊界

          在Javascript里,我們都是使用 try/catch 來捕捉可能發(fā)生的異常,在catch中處理錯誤。比如:

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

          這樣, 即便發(fā)生了錯誤, 我們的應用也不至于崩潰白屏。

          React 歸根結底也是Javascript,本質上沒什么不同, 所以同樣的使用try/catch ?也沒有問題。

          然而, 由于React 實現(xiàn)機制的原因, 發(fā)生在組件內(nèi)部的Javascript 錯誤會破壞內(nèi)部狀態(tài), render會產(chǎn)生錯誤:

          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 <h1>Something went wrong.h1>
          }
          return this.props.children
          }
          }

          使用方式:


          <MyWidget />
          ErrorBoundary>

          Live Demo By Dan Abramov:

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

          3.高階組件

          通俗點講, 所謂高階組件就是, 你丟一個組件進去, 增加一些屬性或操作, 再丟出來。

          一般來說, 你可以把一些具備共同點的組件抽象成一個高階組件, 然后再不同的模塊中復用。

          比如, 我們的系統(tǒng)中, 有一類按鈕要加個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 (
          <div style={style} {...rest}>
          <h2>
          This is my component and I am expecting some styles.
          h2>

          div>
          )
          }

          export default withBorder(MyComponent, { border: '4px solid teal' })

          經(jīng)過withBorder裝飾的MyComponent組件, 就具備了統(tǒng)一border這項功能, 后面如果如果要做修改, 就可以在這個中間層統(tǒng)一處理, 非常方便。

          在我的項目里, 也用了一些高階組件, 舉個具體的例子:

          PackEditor = withTranslate(PackEditor)

          我們的這個 PackEditor 就是一個增強過的組件, 增加了什么功能呢?

          正如名字表述的, withTranslate, 增加了一個翻譯功能, 下面也給大家看看這個組件是怎么實現(xiàn)的:

          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 }) => (
          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 (


          {...props}
          />


          )
          }

          export default withTranslate

          用法很靈過:

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

          )
          })

          十分的方便。

          4. Render props

          Rrender prop 是指一種在 React 組件之間使用一個值為函數(shù)的 prop 共享代碼的簡單技術, 和 HOC 類似, 都是組件間的邏輯復用問題。

          更具體地說,Render prop 是一個用于告知組件需要渲染什么內(nèi)容的函數(shù)。

          下面看一下簡單的例子:

          以下組件跟蹤 Web 應用程序中的鼠標位置:

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

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

          render() {
          return (
          <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
          <p>The current mouse position is ({this.state.x}, {this.state.y})p>

          div>
          );
          }
          }

          class MouseTracker extends React.Component {
          render() {
          return (
          <>
          <h1>移動鼠標!h1>

          <Mouse />

          );
          }
          }

          當光標在屏幕上移動時,組件顯示其(x,y)坐標。

          現(xiàn)在的問題是:

          我們?nèi)绾卧诹硪粋€組件中復用這個行為?

          換個說法,若另一個組件需要知道鼠標位置,我們能否封裝這一行為,以便輕松地與其他組件共享它??

          假設產(chǎn)品想要這樣一個功能:在屏幕上呈現(xiàn)一張在屏幕上追逐鼠標的貓的圖片。

          我們或許會使用

          class Cat extends React.Component {
          render() {
          const mouse = this.props.mouse;
          return (
          <img src="" 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 (
          '100%' }} onMouseMove={this.handleMouseMove}>
          this.state} />

          );
          }
          }

          巴適~ 簡單粗暴, 一分鐘完成任務。

          可是,如果下次產(chǎn)品再要想加條狗呢?

          以上的例子,雖然可以完成了貓追鼠標的需求,還沒有達到以可復用的方式真正封裝行為的目標。

          當我們想要鼠標位置用于不同的用例時,我們必須創(chuàng)建一個新的組件,專門為該用例呈現(xiàn)一些東西.

          這也是 render prop 的來歷:

          我們可以提供一個帶有函數(shù) prop 的組件,它能夠動態(tài)決定什么需要渲染的,而不是將硬編碼到組件里.

          修改一下上面的代碼:

          class Cat extends React.Component {
          render() {
          const mouse = this.props.mouse;
          return (

          );
          }
          }


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

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

          render() {
          return (
          <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
          {this.props.render(this.state)}
          div>

          );
          }
          }

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

          移動鼠標!


          (

          )}/>

          );
          }
          }

          提供了一個render 方法,讓動態(tài)決定什么需要渲染。

          事實上,render prop 是因為模式才被稱為 render prop ,不一定要用名為 render 的 prop 來使用這種模式。

          任何被用于告知組件需要渲染什么內(nèi)容的函數(shù) prop, 在技術上都可以被稱為 "render prop".

          另外,關于 render prop 一個有趣的事情是你可以使用帶有 render prop 的常規(guī)組件來實現(xiàn)大多數(shù)高階組件 (HOC)。

          例如,如果你更喜歡使用 withMouse HOC 而不是組件,你可以使用帶有 render prop 的常規(guī)輕松創(chuàng)建一個:

          function withMouse(Component) {
          return class extends React.Component {
          render() {
          return (
          (

          )}/>
          );
          }
          }
          }

          也是非常的簡潔清晰。

          有一點需要注意的是, 如果你在定義的render函數(shù)里創(chuàng)建函數(shù), 使用 render prop 會抵消使用 React.PureComponent 帶來的優(yōu)勢。

          因為淺比較 props 的時候總會得到 false,并且在這種情況下每一個 render 對于 render prop 將會生成一個新的值。

          class Mouse extends React.PureComponent {
          // 與上面相同的代碼......
          }

          class MouseTracker extends React.Component {
          render() {
          return (
          <>
          ( // 這是不好的!每個渲染的 `render` prop的值將會是不同的。

          )}/>

          );
          }
          }

          在這樣例子中,每次渲染,它會生成一個新的函數(shù)作為的 prop,因而在同時也抵消了繼承自 React.PureComponent 的組件的效果!

          為了繞過這一問題,有時你可以定義一個 prop 作為實例方法,類似這樣:

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

          render() {
          return (

          Move the mouse around!




          );
          }
          }

          5.組件性能

          性能優(yōu)化是永恒的主題, 這里不一一細說, 提供幾份資源供你參考:

          • React.memo https://reactjs.org/docs/react-api.html#reactmemo
          • React.useMemo ?https://flaviocopes.com/react-hook-usememo/
          • React.useCallback https://reactjs.org/docs/hooks-reference.html#usecallback
          • React.PureComponent https://reactjs.org/docs/react-api.html#reactpurecomponent
          • Optimizing performance https://reactjs.org/docs/optimizing-performance.html

          總結

          以上幾點都是我們經(jīng)常要使用的技巧, 簡單實用, 分享給大家, 希望能給大家?guī)硪恍椭騿l(fā),謝謝。


          最后



          如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:

          1. 點個「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點在看,都是耍流氓 -_-)

          2. 歡迎加我微信「qianyu443033099」拉你進技術群,長期交流學習...

          3. 關注公眾號「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。


          點個在看支持我吧,轉發(fā)就更好了



          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美色图小说 | 性爱激情五月 | 亚洲无码天堂在线视频 | 国产中文字幕在线 | 字幕一区二区久久人妻网站 |