<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>

          干貨!介紹4個(gè)實(shí)用的React實(shí)踐技巧

          共 11217字,需瀏覽 23分鐘

           ·

          2021-05-17 16:18

          背景


          Hooks 自推出以來(lái)就很火, 它改變了我們編寫React 代碼的方式, 有助于我們寫更簡(jiǎn)潔的代碼。

          今天這邊文章不是說(shuō)Hooks的,Hooks之外, 還有很多實(shí)用的技巧可以幫助我們便攜簡(jiǎn)潔實(shí)用的代碼。

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

          正文





          1. 使用字符串來(lái)定義一個(gè)React元素

          舉個(gè)簡(jiǎn)單的例子:

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

          const MyComponent = 'div'

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

          React 內(nèi)部會(huì)調(diào)用 React.createElement, 使用這個(gè)字符串來(lái)生成這個(gè)元素。

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

          // 定義一個(gè)MyComponent
          function MyComponent({ component: Component = 'div', 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="div" name="KK" age={18} email="[email protected]">
          </>
          )
          }

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

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

          )
          }

          function App() {
          return (
          <>
          <MyComponent component={Dashboard} name="KK" age={18} email="[email protected]">
          </>
          )
          }

          如果你遇到處理一類相似的元素或者組件,可以通過(guò)這種自定義的方式抽象出來(lái),簡(jiǎn)化你的代碼。

          舉個(gè)現(xiàn)實(shí)的例子:

          比如我們現(xiàn)在要做一個(gè)貨物打包的需求, 可以單個(gè)打, 也可以批量打, 針對(duì)共同點(diǎ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è)務(wù)模塊中, 就可以靈活的使用了, 非常方便。

          2. 定義錯(cuò)誤邊界

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

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

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

          React 歸根結(jié)底也是Javascript,本質(zhì)上沒(méi)什么不同, 所以同樣的使用try/catch  也沒(méi)有問(wèn)題。

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

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

          基于以上原因,React 團(tuán)隊(duì)引入了Error Boundaries:

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

          Error boundaries, 其實(shí)就是React組件, 你可以用找個(gè)組件來(lái)處理它捕捉到的任何錯(cuò)誤信息。

          當(dāng)組件樹(shù)崩潰的時(shí)候,也可以顯示你自定義的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.高階組件

          通俗點(diǎn)講, 所謂高階組件就是, 你丟一個(gè)組件進(jìn)去, 增加一些屬性或操作, 再丟出來(lái)。

          一般來(lái)說(shuō), 你可以把一些具備共同點(diǎn)的組件抽象成一個(gè)高階組件, 然后再不同的模塊中復(fù)用。

          比如, 我們的系統(tǒng)中, 有一類按鈕要加個(gè)border, 很多地方都要用到, 我們把它抽象出來(lái):

          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)過(guò)withBorder裝飾的MyComponent組件, 就具備了統(tǒng)一border這項(xiàng)功能, 后面如果如果要做修改, 就可以在這個(gè)中間層統(tǒng)一處理, 非常方便。

          在我的項(xiàng)目里, 也用了一些高階組件, 舉個(gè)具體的例子:

          PackEditor = withTranslate(PackEditor)

          我們的這個(gè) PackEditor 就是一個(gè)增強(qiáng)過(guò)的組件, 增加了什么功能呢?

          正如名字表述的, withTranslate, 增加了一個(gè)翻譯功能, 下面也給大家看看這個(gè)組件是怎么實(shí)現(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 }) => (
          <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

          用法很靈過(guò):

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

          十分的方便。

          4. Render props

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

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

          下面看一下簡(jiǎn)單的例子:

          以下組件跟蹤 Web 應(yīng)用程序中的鼠標(biāo)位置:

          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>移動(dòng)鼠標(biāo)!</h1>
          <Mouse />
          </>
          );
          }
          }

          當(dāng)光標(biāo)在屏幕上移動(dòng)時(shí),組件顯示其(x,y)坐標(biāo)。

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

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

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

          假設(shè)產(chǎn)品想要這樣一個(gè)功能:在屏幕上呈現(xiàn)一張?jiān)谄聊簧献分鹗髽?biāo)的貓的圖片。

          我們或許會(huì)使用 <Cat mouse={{ x, y }} prop 來(lái)告訴組件鼠標(biāo)的坐標(biāo)以讓它知道圖片應(yīng)該在屏幕哪個(gè)位置。

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

          這個(gè)需求如此簡(jiǎn)單,你可能就直接修改Mouse組件了:

              
          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}>
          <Cat mouse={this.state} />
          </div>
          );
          }
          }

          巴適~ 簡(jiǎn)單粗暴, 一分鐘完成任務(wù)。

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

          以上的例子,雖然可以完成了貓追鼠標(biāo)的需求,還沒(méi)有達(dá)到以可復(fù)用的方式真正封裝行為的目標(biāo)。

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

          這也是 render prop 的來(lái)歷:

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

          修改一下上面的代碼:

          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 (
          <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
          {this.props.render(this.state)}
          </div>

          );
          }
          }

          class MouseTracker extends React.Component {
          render() {
          return (
          <div>
          <h1>移動(dòng)鼠標(biāo)!</h1>
          <Mouse render={mouse => (
          <Cat mouse={mouse} />
          )}/>
          </div>
          );
          }
          }

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

          事實(shí)上,render prop 是因?yàn)槟J讲疟环Q為 render prop ,不一定要用名為 render 的 prop 來(lái)使用這種模式。

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

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

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

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

          也是非常的簡(jiǎn)潔清晰。

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

          因?yàn)闇\比較 props 的時(shí)候總會(huì)得到 false,并且在這種情況下每一個(gè) render 對(duì)于 render prop 將會(huì)生成一個(gè)新的值。

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

          class MouseTracker extends React.Component {
          render() {
          return (
          <>
          <Mouse render={mouse => ( // 這是不好的!每個(gè)渲染的 `render` prop的值將會(huì)是不同的。
          <Cat mouse={mouse} />
          )}/>
          </>
          );
          }
          }

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

          為了繞過(guò)這一問(wèn)題,有時(shí)你可以定義一個(gè) prop 作為實(shí)例方法,類似這樣:

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

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

          5.組件性能

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

          • 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

          總結(jié)

          以上幾點(diǎn)都是我們經(jīng)常要使用的技巧, 簡(jiǎn)單實(shí)用, 分享給大家, 希望能給大家?guī)?lái)一些幫助或啟發(fā),謝謝。

          最后


          如果你覺(jué)得這篇內(nèi)容對(duì)你挺有啟發(fā),我想邀請(qǐng)你幫我三個(gè)小忙:
          1. 點(diǎn)個(gè)「在看」,讓更多的人也能看到這篇內(nèi)容。

          2. 關(guān)注公眾號(hào)「前端e進(jìn)階」,掌握前端面試重難點(diǎn),公眾號(hào)后臺(tái)回復(fù)「加群」和小伙伴們暢聊技術(shù)。

          往期精彩回顧:

          [第25期] 你不知道的 CSS - by Chrome 2019

          [第24期] 手把手教你寫幾個(gè)實(shí)用的 React Hooks

          [第23期] 五分鐘搞懂 React Hooks 工作原理

          [第22期] React Conf 2019  樣式新方案

          [第12期]深入了解強(qiáng)大的 ES6 「 ... 」 運(yùn)算符

          [第20期] 全面了解 ES6 Modules

          Shopee 前端內(nèi)部推薦
          瀏覽 47
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  大香蕉伊人成人电影 | 波多野结衣三区 | 99麻豆 | 在线观看亚洲免费视频 | 色婷婷免费在线视频 |