欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React中組件復(fù)用的方式總結(jié)

 更新時間:2023年06月02日 11:38:45   作者:WindrunnerMax  
這篇文章主要為大家詳細(xì)介紹了Mixin、HOC、Render?Props、Hooks這四種組件間復(fù)用的方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下

React組件復(fù)用的方式

現(xiàn)前端的工程化越發(fā)重要,雖然使用Ctrl+CCtrl+V同樣能夠完成需求,但是一旦面臨修改那就是一項龐大的任務(wù),于是減少代碼的拷貝,增加封裝復(fù)用能力,實現(xiàn)可維護、可復(fù)用的代碼就變得尤為重要,在React中組件是代碼復(fù)用的主要單元,基于組合的組件復(fù)用機制相當(dāng)優(yōu)雅,而對于更細(xì)粒度的邏輯(狀態(tài)邏輯、行為邏輯等),復(fù)用起來卻不那么容易,很難把狀態(tài)邏輯拆出來作為一個可復(fù)用的函數(shù)或組件,實際上在Hooks出現(xiàn)之前,都缺少一種簡單直接的組件行為擴展方式,對于Mixin、HOCRender Props都算是在既有(組件機制的)游戲規(guī)則下探索出來的上層模式,一直沒有從根源上很好地解決組件間邏輯復(fù)用的問題,直到Hooks登上舞臺,下面我們就來介紹一下Mixin、HOC、Render Props、Hooks四種組件間復(fù)用的方式。

Mixin

當(dāng)然React很久之前就不再建議使用Mixin作為復(fù)用的解決方案,但是現(xiàn)在依舊能通過create-react-class提供對Mixin的支持,此外注意在以ES6class方式聲明組件時是不支持Mixin的。
Mixins允許多個React組件之間共享代碼,它們非常類似于Python中的mixinsPHP中的traits,Mixin方案的出現(xiàn)源自一種OOP直覺,只在早期提供了React.createClass() API(React v15.5.0正式廢棄,移至create-react-class)來定義組件,自然而然地,(類)繼承就成了一種直覺性的嘗試,而在JavaScript基于原型的擴展模式下,類似于繼承的Mixin方案就成了一個不錯的解決方案,Mixin主要用來解決生命周期邏輯和狀態(tài)邏輯的復(fù)用問題,允許從外部擴展組件生命周期,在Flux等模式中尤為重要,但是在不斷實踐中也出現(xiàn)了很多缺陷:

  • 組件與Mixin之間存在隱式依賴(Mixin經(jīng)常依賴組件的特定方法,但在定義組件時并不知道這種依賴關(guān)系)。
  • 多個Mixin之間可能產(chǎn)生沖突(比如定義了相同的state字段)。
  • Mixin傾向于增加更多狀態(tài),這降低了應(yīng)用的可預(yù)測性,導(dǎo)致復(fù)雜度劇增。
  • 隱式依賴導(dǎo)致依賴關(guān)系不透明,維護成本和理解成本迅速攀升。
  • 難以快速理解組件行為,需要全盤了解所有依賴Mixin的擴展行為,及其之間的相互影響
  • 組件自身的方法和state字段不敢輕易刪改,因為難以確定有沒有Mixin依賴它。
  • Mixin也難以維護,因為Mixin邏輯最后會被打平合并到一起,很難搞清楚一個Mixin的輸入輸出。

毫無疑問,這些問題是致命的,所以,Reactv0.13.0放棄了Mixin靜態(tài)橫切(類似于繼承的復(fù)用),轉(zhuǎn)而走向HOC高階組件(類似于組合的復(fù)用)。

示例

上古版本示例,一個通用的場景是: 一個組件需要定期更新,用setInterval()做很容易,但當(dāng)不需要它的時候取消定時器來節(jié)省內(nèi)存是非常重要的,React提供生命周期方法來告知組件創(chuàng)建或銷毀的時間,下面的Mixin,使用setInterval()并保證在組件銷毀時清理定時器。

var SetIntervalMixin = {
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
    this.intervals.forEach(clearInterval);
  }
};
var TickTock = React.createClass({
  mixins: [SetIntervalMixin], // 引用 mixin
  getInitialState: function() {
    return {seconds: 0};
  },
  componentDidMount: function() {
    this.setInterval(this.tick, 1000); // 調(diào)用 mixin 的方法
  },
  tick: function() {
    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {
    return (
      <p>
        React has been running for {this.state.seconds} seconds.
      </p>
    );
  }
});
ReactDOM.render(
  <TickTock />,
  document.getElementById("example")
);

HOC

Mixin之后,HOC高階組件擔(dān)起重任,成為組件間邏輯復(fù)用的推薦方案,高階組件從名字上就透漏出高級的氣息,實際上這個概念應(yīng)該是源自于JavaScript的高階函數(shù),高階函數(shù)就是接受函數(shù)作為輸入或者輸出的函數(shù),可以想到柯里化就是一種高階函數(shù),同樣在React文檔上也給出了高階組件的定義,高階組件是接收組件并返回新組件的函數(shù)。具體的意思就是: 高階組件可以看作React對裝飾模式的一種實現(xiàn),高階組件就是一個函數(shù),且該函數(shù)接受一個組件作為參數(shù),并返回一個新的組件,他會返回一個增強的React組件,高階組件可以讓我們的代碼更具有復(fù)用性,邏輯性與抽象性,可以對render方法進(jìn)行劫持,也可以控制propsstate等。

對比MixinHOC,Mixin是一種混入的模式,在實際使用中Mixin的作用還是非常強大的,能夠使得我們在多個組件中共用相同的方法,但同樣也會給組件不斷增加新的方法和屬性,組件本身不僅可以感知,甚至需要做相關(guān)的處理(例如命名沖突、狀態(tài)維護等),一旦混入的模塊變多時,整個組件就變的難以維護,Mixin可能會引入不可見的屬性,例如在渲染組件中使用Mixin方法,給組件帶來了不可見的屬性props和狀態(tài)state,并且Mixin可能會相互依賴,相互耦合,不利于代碼維護,此外不同的Mixin中的方法可能會相互沖突。之前React官方建議使用Mixin用于解決橫切關(guān)注點相關(guān)的問題,但由于使用Mixin可能會產(chǎn)生更多麻煩,所以官方現(xiàn)在推薦使用HOC。高階組件HOC屬于函數(shù)式編程functional programming思想,對于被包裹的組件時不會感知到高階組件的存在,而高階組件返回的組件會在原來的組件之上具有功能增強的效果,基于此React官方推薦使用高階組件。

HOC雖然沒有那么多致命問題,但也存在一些小缺陷:

  • 擴展性限制: HOC并不能完全替代Mixin,一些場景下,Mixin可以而HOC做不到,比如PureRenderMixin,因為HOC無法從外部訪問子組件的State,同時通過shouldComponentUpdate濾掉不必要的更新,因此,React在支持ES6Class之后提供了React.PureComponent來解決這個問題。
  • Ref傳遞問題: Ref被隔斷,Ref的傳遞問題在層層包裝下相當(dāng)惱人,函數(shù)Ref能夠緩解一部分(讓HOC得以獲知節(jié)點創(chuàng)建與銷毀),以致于后來有了React.forwardRef API。
  • WrapperHell: HOC泛濫,出現(xiàn)WrapperHell(沒有包一層解決不了的問題,如果有,那就包兩層),多層抽象同樣增加了復(fù)雜度和理解成本,這是最關(guān)鍵的缺陷,而HOC模式下沒有很好的解決辦法。

示例

具體而言,高階組件是參數(shù)為組件,返回值為新組件的函數(shù),組件是將props轉(zhuǎn)換為UI,而高階組件是將組件轉(zhuǎn)換為另一個組件。HOCReact的第三方庫中很常見,例如ReduxconnectRelaycreateFragmentContainer。

// 高階組件定義
const higherOrderComponent = (WrappedComponent) => {
    return class EnhancedComponent extends React.Component {
        // ...
        render() {
          return <WrappedComponent {...this.props} />;
        }
  };
}
// 普通組件定義
class WrappedComponent extends React.Component{
    render(){
        //....
    }
}
// 返回被高階組件包裝過的增強組件
const EnhancedComponent = higherOrderComponent(WrappedComponent);

在這里要注意,不要試圖以任何方式在HOC中修改組件原型,而應(yīng)該使用組合的方式,通過將組件包裝在容器組件中實現(xiàn)功能。通常情況下,實現(xiàn)高階組件的方式有以下兩種:

  • 屬性代理Props Proxy
  • 反向繼承Inheritance Inversion。

屬性代理

例如我們可以為傳入的組件增加一個存儲中的id屬性值,通過高階組件我們就可以為這個組件新增一個props,當(dāng)然我們也可以對在JSX中的WrappedComponent組件中props進(jìn)行操作,注意不是操作傳入的WrappedComponent類,我們不應(yīng)該直接修改傳入的組件,而可以在組合的過程中對其操作。

const HOC = (WrappedComponent, store) => {
    return class EnhancedComponent extends React.Component {
        render() {
            const newProps = {
                id: store.id
            }
            return <WrappedComponent
                {...this.props}
                {...newProps}
            />;
        }
    }
}

我們也可以利用高階組件將新組件的狀態(tài)裝入到被包裝組件中,例如我們可以使用高階組件將非受控組件轉(zhuǎn)化為受控組件。

class WrappedComponent extends React.Component {
    render() {
        return <input name="name" />;
    }
}
const HOC = (WrappedComponent) => {
    return class EnhancedComponent extends React.Component {
        constructor(props) {
            super(props);
            this.state = { name: "" };
        }
        render() {
            const newProps = {
                value: this.state.name,
                onChange: e => this.setState({name: e.target.value}),
            }
            return <WrappedComponent 
                {...this.props} 
                {...newProps} 
            />;
        }
    }
}

或者我們的目的是將其使用其他組件包裹起來用以達(dá)成布局或者是樣式的目的。

const HOC = (WrappedComponent) => {
    return class EnhancedComponent extends React.Component {
        render() {
            return (
                <div class="layout">
                    <WrappedComponent  {...this.props} />
                </div>
            );
        }
    }
}

反向繼承

反向繼承是指返回的組件去繼承之前的組件,在反向繼承中我們可以做非常多的操作,修改state、props甚至是翻轉(zhuǎn)Element Tree,反向繼承有一個重要的點,反向繼承不能保證完整的子組件樹被解析,也就是說解析的元素樹中包含了組件(函數(shù)類型或者Class類型),就不能再操作組件的子組件了。
當(dāng)我們使用反向繼承實現(xiàn)高階組件的時候可以通過渲染劫持來控制渲染,具體是指我們可以有意識地控制WrappedComponent的渲染過程,從而控制渲染控制的結(jié)果,例如我們可以根據(jù)部分參數(shù)去決定是否渲染組件。

const HOC = (WrappedComponent) => {
    return class EnhancedComponent extends WrappedComponent {
        render() {
            return this.props.isRender && super.render();  
        }
    }
}

甚至我們可以通過重寫的方式劫持原組件的生命周期。

const HOC = (WrappedComponent) => {
    return class EnhancedComponent extends WrappedComponent {
        componentDidMount(){
          // ...
        }
        render() {
            return super.render();  
        }
    }
}

由于實際上是繼承關(guān)系,我們可以去讀取組件的propsstate,如果有必要的話,甚至可以修改增加、修改和刪除propsstate,當(dāng)然前提是修改帶來的風(fēng)險需要你自己來控制。在一些情況下,我們可能需要為高階屬性傳入一些參數(shù),那我們就可以通過柯里化的形式傳入?yún)?shù),配合高階組件可以完成對組件的類似于閉包的操作。

const HOCFactoryFactory = (params) => {
    // 此處操作params
    return (WrappedComponent) => {
        return class EnhancedComponent extends WrappedComponent {
            render() {
                return params.isRender && this.props.isRender && super.render();
            }
        }
    }
}

注意

不要改變原始組件

不要試圖在HOC中修改組件原型,或以其他方式改變它。

function logProps(InputComponent) {
  InputComponent.prototype.componentDidUpdate = function(prevProps) {
    console.log("Current props: ", this.props);
    console.log("Previous props: ", prevProps);
  };
  // 返回原始的 input 組件,其已經(jīng)被修改。
  return InputComponent;
}
// 每次調(diào)用 logProps 時,增強組件都會有 log 輸出。
const EnhancedComponent = logProps(InputComponent);

這樣做會產(chǎn)生一些不良后果,其一是輸入組件再也無法像HOC增強之前那樣使用了,更嚴(yán)重的是,如果你再用另一個同樣會修改componentDidUpdateHOC增強它,那么前面的HOC就會失效,同時這個HOC也無法應(yīng)用于沒有生命周期的函數(shù)組件。

修改傳入組件的HOC是一種糟糕的抽象方式,調(diào)用者必須知道他們是如何實現(xiàn)的,以避免與其他HOC發(fā)生沖突。HOC不應(yīng)該修改傳入組件,而應(yīng)該使用組合的方式,通過將組件包裝在容器組件中實現(xiàn)功能。

function logProps(WrappedComponent) {
  return class extends React.Component {
    componentDidUpdate(prevProps) {
      console.log("Current props: ", this.props);
      console.log("Previous props: ", prevProps);
    }
    render() {
      // 將 input 組件包裝在容器中,而不對其進(jìn)行修改,Nice!
      return <WrappedComponent {...this.props} />;
    }
  }
}

過濾props

HOC為組件添加特性,自身不應(yīng)該大幅改變約定,HOC返回的組件與原組件應(yīng)保持類似的接口。HOC應(yīng)該透傳與自身無關(guān)的props,大多數(shù)HOC都應(yīng)該包含一個類似于下面的render方法。

render() {
  // 過濾掉額外的 props,且不要進(jìn)行透傳
  const { extraProp, ...passThroughProps } = this.props;
  // 將 props 注入到被包裝的組件中。
  // 通常為 state 的值或者實例方法。
  const injectedProp = someStateOrInstanceMethod;
  // 將 props 傳遞給被包裝組件
  return (
    <WrappedComponent
      injectedProp={injectedProp}
      {...passThroughProps}
    />
  );
}

最大化可組合性

并不是所有的HOC都一樣,有時候它僅接受一個參數(shù),也就是被包裹的組件。

const NavbarWithRouter = withRouter(Navbar);

HOC通??梢越邮斩鄠€參數(shù),比如在RelayHOC額外接收了一個配置對象用于指定組件的數(shù)據(jù)依賴。

const CommentWithRelay = Relay.createContainer(Comment, config);

最常見的HOC簽名如下,connect是一個返回高階組件的高階函數(shù)。

// React Redux 的 `connect` 函數(shù)
const ConnectedComment = connect(commentSelector, commentActions)(CommentList);
// connect 是一個函數(shù),它的返回值為另外一個函數(shù)。
const enhance = connect(commentListSelector, commentListActions);
// 返回值為 HOC,它會返回已經(jīng)連接 Redux store 的組件
const ConnectedComment = enhance(CommentList);

這種形式可能看起來令人困惑或不必要,但它有一個有用的屬性,像connect函數(shù)返回的單參數(shù)HOC具有簽名Component => Component,輸出類型與輸入類型相同的函數(shù)很容易組合在一起。同樣的屬性也允許connect和其他HOC承擔(dān)裝飾器的角色。此外許多第三方庫都提供了compose工具函數(shù),包括lodash、ReduxRamda。

const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))
// 你可以編寫組合工具函數(shù)
// compose(f, g, h) 等同于 (...args) => f(g(h(...args)))
const enhance = compose(
  // 這些都是單參數(shù)的 HOC
  withRouter,
  connect(commentSelector)
)
const EnhancedComponent = enhance(WrappedComponent)

不要在render方法中使用HOC

Reactdiff算法使用組件標(biāo)識來確定它是應(yīng)該更新現(xiàn)有子樹還是將其丟棄并掛載新子樹,如果從render返回的組件與前一個渲染中的組件相同===,則React通過將子樹與新子樹進(jìn)行區(qū)分來遞歸更新子樹,如果它們不相等,則完全卸載前一個子樹。

通常在使用的時候不需要考慮這點,但對HOC來說這一點很重要,因為這代表著你不應(yīng)在組件的render方法中對一個組件應(yīng)用HOC。

render() {
  // 每次調(diào)用 render 函數(shù)都會創(chuàng)建一個新的 EnhancedComponent
  // EnhancedComponent1 !== EnhancedComponent2
  const EnhancedComponent = enhance(MyComponent);
  // 這將導(dǎo)致子樹每次渲染都會進(jìn)行卸載,和重新掛載的操作!
  return <EnhancedComponent />;
}

這不僅僅是性能問題,重新掛載組件會導(dǎo)致該組件及其所有子組件的狀態(tài)丟失,如果在組件之外創(chuàng)建HOC,這樣一來組件只會創(chuàng)建一次。因此每次render時都會是同一個組件,一般來說,這跟你的預(yù)期表現(xiàn)是一致的。在極少數(shù)情況下,你需要動態(tài)調(diào)用HOC,你可以在組件的生命周期方法或其構(gòu)造函數(shù)中進(jìn)行調(diào)用。

務(wù)必復(fù)制靜態(tài)方法

有時在React組件上定義靜態(tài)方法很有用,例如Relay容器暴露了一個靜態(tài)方法getFragment以方便組合GraphQL片段。但是當(dāng)你將HOC應(yīng)用于組件時,原始組件將使用容器組件進(jìn)行包裝,這意味著新組件沒有原始組件的任何靜態(tài)方法。

// 定義靜態(tài)函數(shù)
WrappedComponent.staticMethod = function() {/*...*/}
// 現(xiàn)在使用 HOC
const EnhancedComponent = enhance(WrappedComponent);
// 增強組件沒有 staticMethod
typeof EnhancedComponent.staticMethod === "undefined" // true

為了解決這個問題,你可以在返回之前把這些方法拷貝到容器組件上。

function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  // 必須準(zhǔn)確知道應(yīng)該拷貝哪些方法 :(
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}

但要這樣做,你需要知道哪些方法應(yīng)該被拷貝,你可以使用hoist-non-react-statics依賴自動拷貝所有非React靜態(tài)方法。

import hoistNonReactStatic from "hoist-non-react-statics";
function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  hoistNonReactStatic(Enhance, WrappedComponent);
  return Enhance;
}

除了導(dǎo)出組件,另一個可行的方案是再額外導(dǎo)出這個靜態(tài)方法。

// 使用這種方式代替...
MyComponent.someFunction = someFunction;
export default MyComponent;
// ...單獨導(dǎo)出該方法...
export { someFunction };
// ...并在要使用的組件中,import 它們
import MyComponent, { someFunction } from "./MyComponent.js";

Refs不會被傳遞

雖然高階組件的約定是將所有props傳遞給被包裝組件,但這對于refs并不適用,那是因為ref實際上并不是一個prop,就像key一樣,它是由React專門處理的。如果將ref添加到HOC的返回組件中,則ref引用指向容器組件,而不是被包裝組件,這個問題可以通過React.forwardRef這個API明確地將refs轉(zhuǎn)發(fā)到內(nèi)部的組件。。

function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }
    render() {
      const {forwardedRef, ...rest} = this.props;
      // 將自定義的 prop 屬性 “forwardedRef” 定義為 ref
      return <Component ref={forwardedRef} {...rest} />;
    }
  }
  // 注意 React.forwardRef 回調(diào)的第二個參數(shù) “ref”。
  // 我們可以將其作為常規(guī) prop 屬性傳遞給 LogProps,例如 “forwardedRef”
  // 然后它就可以被掛載到被 LogProps 包裹的子組件上。
  return React.forwardRef((props, ref) => {
    return <LogProps {...props} forwardedRef={ref} />;
  });
}

Render Props

HOC一樣,Render Props也是一直以來都存在的元老級模式,render props指在一種React組件之間使用一個值為函數(shù)的props共享代碼的簡單技術(shù),具有render props的組件接收一個函數(shù),該函數(shù)返回一個React元素并調(diào)用它而不是實現(xiàn)一個自己的渲染邏輯,render props是一個用于告知組件需要渲染什么內(nèi)容的函數(shù)props,也是組件邏輯復(fù)用的一種實現(xiàn)方式,簡單來說就是在被復(fù)用的組件中,通過一個名為render(屬性名也可以不是render,只要值是一個函數(shù)即可)的prop屬性,該屬性是一個函數(shù),這個函數(shù)接受一個對象并返回一個子組件,會將這個函數(shù)參數(shù)中的對象作為props傳入給新生成的組件,而在使用調(diào)用者組件這里,只需要決定這個組件在哪里渲染以及該以何種邏輯渲染并傳入相關(guān)對象即可。

對比HOCRender Props,技術(shù)上,二者都基于組件組合機制,Render Props擁有與HOC 一樣的擴展能力,稱之為Render Props,并不是說只能用來復(fù)用渲染邏輯,而是表示在這種模式下,組件是通過render()組合起來的,類似于HOC 模式下通過Wrapperrender()建立組合關(guān)系形式上,二者非常相像,同樣都會產(chǎn)生一層Wrapper,而實際上Render Props HOC 甚至能夠相互轉(zhuǎn)換。

同樣,Render Props也會存在一些問題:

  • 數(shù)據(jù)流向更直觀了,子孫組件可以很明確地看到數(shù)據(jù)來源,但本質(zhì)上Render Props是基于閉包實現(xiàn)的,大量地用于組件的復(fù)用將不可避免地引入了callback hell問題。
  • 丟失了組件的上下文,因此沒有this.props屬性,不能像HOC那樣訪問this.props.children。

示例

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>React</title>
</head>
<body>
    <div id="root"></div>
</body>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
class MouseTracker extends React.Component {
  constructor(props) {
    super(props);
    this.state = { x: 0,  y: 0, }
  }
  handleMouseMove = (event) => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }
  render() {
    return (
      <div onMouseMove={this.handleMouseMove}>
        {this.props.render(this.state)} {/* Render Props */}
      </div>
    )
  }
}
class MouseLocation extends React.Component {
  render() {
    return (
      <>
        <h1>請在此處移動鼠標(biāo)</h1>
        <p>當(dāng)前鼠標(biāo)的位置是: x:{this.props.mouse.x} y:{this.props.mouse.y}</p>
      </>
    )
  }
}
ReactDOM.render(
  <MouseTracker render={mouse => <MouseLocation mouse={mouse} />}></MouseTracker>, 
  document.getElementById("root")
);
</script>
</html>

Hooks

代碼復(fù)用的解決方案層出不窮,但是整體來說代碼復(fù)用還是很復(fù)雜的,這其中很大一部分原因在于細(xì)粒度代碼復(fù)用不應(yīng)該與組件復(fù)用捆綁在一起,HOC、Render Props 等基于組件組合的方案,相當(dāng)于先把要復(fù)用的邏輯包裝成組件,再利用組件復(fù)用機制實現(xiàn)邏輯復(fù)用,自然就受限于組件復(fù)用,因而出現(xiàn)擴展能力受限、Ref 隔斷、Wrapper Hell等問題,那么我們就需要有一種簡單直接的代碼復(fù)用方式,函數(shù),將可復(fù)用邏輯抽離成函數(shù)應(yīng)該是最直接、成本最低的代碼復(fù)用方式,但對于狀態(tài)邏輯,仍然需要通過一些抽象模式(如Observable)才能實現(xiàn)復(fù)用,這正是Hooks的思路,將函數(shù)作為最小的代碼復(fù)用單元,同時內(nèi)置一些模式以簡化狀態(tài)邏輯的復(fù)用。比起上面提到的其它方案,Hooks讓組件內(nèi)邏輯復(fù)用不再與組件復(fù)用捆綁在一起,是真正在從下層去嘗試解決(組件間)細(xì)粒度邏輯的復(fù)用問題此外,這種聲明式邏輯復(fù)用方案將組件間的顯式數(shù)據(jù)流與組合思想進(jìn)一步延伸到了組件內(nèi)。

當(dāng)然Hooks也并非完美,只是就目前而言,其缺點如下:

  • 額外的學(xué)習(xí)成本,主要在于Functional ComponentClass Component之間的比較上。
  • 寫法上有限制(不能出現(xiàn)在條件、循環(huán)中),并且寫法限制增加了重構(gòu)成本。
  • 破壞了PureComponent、React.memo淺比較的性能優(yōu)化效果,為了取最新的propsstate,每次render()都要重新創(chuàng)建事件處函數(shù)。
  • 在閉包場景可能會引用到舊的state、props值。
  • 內(nèi)部實現(xiàn)上不直觀,依賴一份可變的全局狀態(tài),不再那么pure。
  • React.memo并不能完全替代shouldComponentUpdate(因為拿不到state change,只針對props change)。
  • useState API設(shè)計上不太完美。

示例

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>React</title>
</head>
<body>
    <div id="root"></div>
</body>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
  const {useState, useEffect} = React;
  function useMouseLocation(location){
    return (
      <>
        <h1>請在此處移動鼠標(biāo)</h1>
        <p>當(dāng)前鼠標(biāo)的位置是: x:{location.x} y:{location.y}</p>
      </>
    );
  }
  function MouseTracker(props){
    const [x, setX] = useState(0);
    const [y, setY] = useState(0);
    function handleMouseMove(event){
        setX(event.clientX);
        setY(event.clientY);
    }
    return (
      <div onMouseMove={handleMouseMove}>
        {useMouseLocation({x, y})}
      </div>
    )
  }
  ReactDOM.render(
    <MouseTracker/>, 
    document.getElementById("root")
  );
</script>
</html>

到此這篇關(guān)于React中組件復(fù)用的方式總結(jié)的文章就介紹到這了,更多相關(guān)React組件復(fù)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文詳解手動實現(xiàn)Recoil狀態(tài)管理基本原理

    一文詳解手動實現(xiàn)Recoil狀態(tài)管理基本原理

    這篇文章主要為大家介紹了一文詳解手動實現(xiàn)Recoil狀態(tài)管理基本原理實例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • React組件設(shè)計過程之仿抖音訂單組件

    React組件設(shè)計過程之仿抖音訂單組件

    這篇文章主要介紹了React組件設(shè)計過程之仿抖音訂單組件的實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • react?源碼中位運算符的使用詳解

    react?源碼中位運算符的使用詳解

    這篇文章主要為大家詳細(xì)介紹了react?位運算符,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • react組件實例屬性props實例詳解

    react組件實例屬性props實例詳解

    這篇文章主要介紹了react組件實例屬性props,本文結(jié)合實例代碼給大家簡單介紹了props使用方法,代碼簡單易懂,需要的朋友可以參考下
    2023-01-01
  • 30行代碼實現(xiàn)React雙向綁定hook的示例代碼

    30行代碼實現(xiàn)React雙向綁定hook的示例代碼

    本文主要介紹了30行代碼實現(xiàn)React雙向綁定hook的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • 深入淺析react native es6語法

    深入淺析react native es6語法

    這篇文章主要介紹了深入淺析react native es6語法的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • React 項目中動態(tài)設(shè)置環(huán)境變量

    React 項目中動態(tài)設(shè)置環(huán)境變量

    本文主要介紹了React 項目中動態(tài)設(shè)置環(huán)境變量,本文將介紹兩種常用的方法,使用 dotenv 庫和通過命令行參數(shù)傳遞環(huán)境變量,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • 詳解React中setState回調(diào)函數(shù)

    詳解React中setState回調(diào)函數(shù)

    這篇文章主要介紹了詳解React中setState回調(diào)函數(shù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • React操作DOM之forwardRef問題

    React操作DOM之forwardRef問題

    這篇文章主要介紹了React操作DOM之forwardRef問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 使用react+redux實現(xiàn)彈出框案例

    使用react+redux實現(xiàn)彈出框案例

    這篇文章主要為大家詳細(xì)介紹了使用react+redux實現(xiàn)彈出框案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評論