通過這周需求的開發,我發現本身在編寫代碼的過程當中不太關注代碼的複用性和可維護性,不經意間就直接簡單的複製粘貼就完事,這樣看起來是實現了功能,可是卻爲之後的開發留下了很大的隱患。因此,這周我特意結合了本身開發過程當中的問題,簡單了了解了一下關於提升React代碼複用性的兩種方法。react
先介紹一下什麼是React的高階組件,設計模式
高階組件是一個函數,接收一個組件,而後返回一個新的組件。數組
const EnhancedComponent = highOrderComponent(WrappedComponent);
要記住的是,雖然名稱是高階組件,可是高階組件不是組件,而是函數!app
既然是函數,那就能夠有參數,有返回值。從上面能夠看出,這個函數接收一個組件WrappedComponent做爲參數 ,返回加工過的新組件EnhancedComponent。其實高階組件就是設計模式裏的裝飾者模式。函數
能夠說,組件是把 props 轉化成 UI,而高階組件是把一個組件轉化成另一個組件。this
下面是一個簡單的高階組件:設計
import React, { Component } from 'react'; export default (WrappedComponent) => { return class EnhancedComponent extends Component { // do something render() { return <WrappedComponent />; //HOC返回的是一個新的組件 } } }
其實,這只是其中的一種高階組件,這個時候高階組件複用的是組件,也就是說在一個通用的組件中添加額外的邏輯,而後返回一個添加了額外方法和參數的新組件。code
另一種高階組件複用的是多個組件中相同的邏輯,返回一個新的組件。我在開發中使用到的就是這種形式的高階組件。它是這樣的形式:component
//組件一 class Component1 extends React.Component { ... } //組件二 class Component2 extends React.Component { ... } //假設組件一和組件二都須要使用相同的函數foo //設計一個能夠複用foo的高階組件 const HOCComponent = (Component, props) => { const obj = { foo1() {}, foo2() {}, ... //這裏表示想添加的其餘參數 }; const newprops = Object.assign({}, obj, props); return <Component {...newprops}/> } //使用該高階組件 let newComponent1 = HOCComponent(Component1, this.props); let newComponent2 = HOCComponent(Component2, this.props);
這樣就能夠實現複用兩個組件相同的函數或者其餘的參數了,不用在每一個組件中都寫重複的代碼。開發
先簡單介紹一下useState這個hook,
用法:
const [state, setState] = useState(initialState);
返回值:state,更新state的函數setState
參數:初始的state:initialState
由於useState這個Hook誕生以前,若是想使用state必須得定義類組件,函數組件沒法使用state,可是組件的演變確定是往輕量化這個方向演變的,因此useState就能夠是函數組件也可使用state。
來看一下下面這個例子:
有一個這樣的場景:
如今有 小A,小B 兩位同窗,每位同窗都處於未穿鞋的狀態,小A穿鞋須要2s,小B穿鞋須要5s,在頁面一中用文字描述兩位同窗的穿鞋狀態變動( 若是小A正在穿鞋中,則在頁面上顯示 '小A正在穿鞋子',若是小A已經穿好了鞋子,則將文字替換爲 '小A已經穿好鞋子')
使用class組件實現是這樣的:
import React from "react"; class Page extends React.Component { state = { data: [ { id: 1, name: "小A", time: "2000" }, { id: 2, name: "小B", time: "5000" } ] }; start(item) { this.setState({ [item.id]: "穿鞋子" }); setTimeout(() => { this.setState({ [item.id]: "穿好鞋子" }); }, item.time); } componentDidMount() { this.state.data.forEach(item => { this.start(item); }); } render() { return ( <div> {this.state.data.map(item => { return ( <h1 key={item.id}> {this.state[item.id] === "穿鞋子" ? `${item.name}正在穿鞋子...` : `${item.name}已經穿好鞋子了`} </h1> ); })} </div> ); } } export default Page;
使用Hook組件實現是這樣的:
自定義Hook以下:
import React, { useState } from "react"; function useHook(item) { const [status, setStatus] = useState("穿鞋子"); setTimeout(() => { setStatus("穿好鞋子"); }, item.time); return ( <h1 key={item.id}> {status === "穿鞋子" ? `${item.name}正在穿鞋子...` : `${item.name}已經穿好鞋子了`} </h1> ); } export default useHook;
引用hook的函數組件
import React from "react"; import useHook from "./useHook"; function Page() { const data = [ { id: 1, name: "小A", time: "2000" }, { id: 2, name: "小B", time: "5000" } ]; return ( <div> {data.map(item => { return useHook(item); })} </div> ); } export default Page;
看起來並無什麼區別嘛,代碼量也沒有減小。
可是,若是小C和小D也要實現這樣的描述,使用定義好的Hook就簡單多了。
import React from "react"; import useHook from "./useHook"; function Page() { const data = [ { id: 1, name: "小C", time: "4000" }, { id: 2, name: "小D", time: "8000" } ]; return ( <div style={{ color: "lightblue" }}> {data.map(item => { return useHook(item); })} </div> ); } export default Page;