摘要:本篇是深入系列的最后一篇,將介紹開(kāi)發(fā)應(yīng)用時(shí),經(jīng)常用到的模式,這些模式并非都有官方名稱,所以有些模式的命名并不一定準(zhǔn)確,請(qǐng)讀者主要關(guān)注模式的內(nèi)容。
React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深對(duì)React的理解,以及在項(xiàng)目中更加靈活地使用React。
本篇是React深入系列的最后一篇,將介紹開(kāi)發(fā)React應(yīng)用時(shí),經(jīng)常用到的模式,這些模式并非都有官方名稱,所以有些模式的命名并不一定準(zhǔn)確,請(qǐng)讀者主要關(guān)注模式的內(nèi)容。
1. 受控組件React 組件的數(shù)據(jù)流是由state和props驅(qū)動(dòng)的,但對(duì)于input、textarea、select等表單元素,因?yàn)榭梢灾苯咏邮沼脩粼诮缑嫔系妮斎?,所以破壞了React中的固有數(shù)據(jù)流。為了解決這個(gè)問(wèn)題,React引入了受控組件,受控組件指input等表單元素顯示的值,仍然是通過(guò)組件的state獲取的,而不是直接顯示用戶在界面上的輸入信息。
受控組件的實(shí)現(xiàn):通過(guò)監(jiān)聽(tīng)表單元素值的變化,改變組件state,根據(jù)state顯示組件最終要展示的值。一個(gè)簡(jiǎn)單的例子如下:
class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: ""}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert("A name was submitted: " + this.state.value); event.preventDefault(); } render() { return (); } }
和受控組件對(duì)應(yīng)的概念是非受控組件,非受控組件通過(guò)ref獲取表單元素的值,在一些場(chǎng)景下有著特有的作用(如設(shè)置表單元素的焦點(diǎn))。
2. 容器組件容器組件和展示組件是一組對(duì)應(yīng)的概念,關(guān)注的是組件邏輯和組件展示的分離。邏輯由容器組件負(fù)責(zé),展示組件聚焦在視圖層的展現(xiàn)上。在React 深入系列2:組件分類(lèi)中已對(duì)容器組件和展示組件作過(guò)詳細(xì)介紹,這里不再贅述。
3. 高階組件高階組件是一種特殊的函數(shù),接收組件作為輸入,輸出一個(gè)新的組件。高階組件的主要作用是封裝組件的通用邏輯,實(shí)現(xiàn)邏輯的復(fù)用。在React 深入系列6:高階組件中已經(jīng)詳細(xì)介紹過(guò)高階組件,這里也不再贅述。
4. Children傳遞首先,這個(gè)模式的命名可能并不恰當(dāng)。這個(gè)模式中,借助React 組件的children屬性,實(shí)現(xiàn)組件間的解耦。常用在一個(gè)組件負(fù)責(zé)UI的框架,框架內(nèi)部的組件可以靈活替換的場(chǎng)景。
一個(gè)示例:
// ModalDialog.js export default function ModalDialog({ children }) { return{ children }; }; // App.js render() {}
ModalDialog組件是UI的框,框內(nèi)組件可以靈活替換。
5. Render PropsRender Props是把組件部分的渲染邏輯封裝到一個(gè)函數(shù)中,利用組件的props接收這個(gè)函數(shù),然后在組件內(nèi)部調(diào)用這個(gè)函數(shù),執(zhí)行封裝的渲染邏輯。
看一個(gè)官方的例子:
class Cat extends React.Component { render() { const mouse = this.props.mouse; return ( ); } } class Mouse extends React.Component { constructor(props) { super(props); this.handleMouseMove = this.handleMouseMove.bind(this); this.state = { x: 0, y: 0 }; } handleMouseMove(event) { this.setState({ x: event.clientX, y: event.clientY }); } render() { return ({/* * Mouse組件并不知道應(yīng)該如何渲染這部分內(nèi)容, * 這部分渲染邏輯是通過(guò)props的render屬性傳遞給Mouse組件 */} {this.props.render(this.state)}); } } class MouseTracker extends React.Component { render() { return (); } }Move the mouse around!
( )}/>
Mouse監(jiān)聽(tīng)鼠標(biāo)的移動(dòng),并將鼠標(biāo)位置保存到state中。但Mouse組件并不知道最終要渲染出的內(nèi)容,需要調(diào)用this.props.render方法,執(zhí)行渲染邏輯。本例中,Cat組件會(huì)渲染到鼠標(biāo)移動(dòng)到的位置,但完全可以使用其他效果來(lái)跟隨鼠標(biāo)的移動(dòng),只需更改render方法即可。由此可見(jiàn),Mouse組件只關(guān)注鼠標(biāo)位置的移動(dòng),而跟隨鼠標(biāo)移動(dòng)的界面效果,由使用Mouse的組件決定。這是一種基于切面編程的思想(了解后端開(kāi)發(fā)的同學(xué)應(yīng)該比較熟悉)。
使用這種模式,一般習(xí)慣將封裝渲染邏輯的函數(shù)賦值給一個(gè)命名為render的組件屬性(如本例所示),但這并不是必需,你也可以使用其他的屬性命名。
這種模式的變種形式是,直接使用React組件自帶的children屬性傳遞。上面的例子改寫(xiě)為:
class Mouse extends React.Component { // 省略 render() { return ({/* * Mouse組件并不知道應(yīng)該如何渲染這部分內(nèi)容, * 這部分渲染邏輯是通過(guò)props的children屬性傳遞給Mouse組件 */} {this.props.children(this.state)}); } } Mouse.propTypes = { children: PropTypes.func.isRequired }; class MouseTracker extends React.Component { render() { return (); } }Move the mouse around!
{mouse => ( )}
注意children的賦值方式。
React Router 和 React-Motion 這兩個(gè)庫(kù)都使用到了Render Props模式。很多場(chǎng)景下,Render Props實(shí)現(xiàn)的功能也可以通過(guò)高階組件實(shí)現(xiàn)。本例也可以用高階組件實(shí)現(xiàn),請(qǐng)讀者自行思考。
6. Provider組件這種模式借助React的context,把組件需要使用的數(shù)據(jù)保存到context,并提供一個(gè)高階組件從context中獲取數(shù)據(jù)。
一個(gè)例子:
先創(chuàng)建MyProvider,將共享數(shù)據(jù)保存到它的context中,MyProvider一般作為最頂層的組件使用,從而確保其他組件都能獲取到context中的數(shù)據(jù):
import React from "react"; import PropTypes from "prop-types"; const contextTypes = { sharedData: PropTypes.shape({ a: PropTypes.bool, b: PropTypes.string, c: PropTypes.object }) }; export class MyProvider extends React.Component { static childContextTypes = contextTypes; getChildContext() { // 假定context中的數(shù)據(jù)從props中獲取 return { sharedData: this.props.sharedData }; } render() { return this.props.children; } }
然后創(chuàng)建高階組件connectData,用于從context中獲取所需數(shù)據(jù):
export const connectData = WrappedComponent => class extends React.Component { static contextTypes = contextTypes; render() { const { props, context } = this; return; } };
最后在應(yīng)用中使用:
const SomeComponentWithData = connectData(SomeComponent) const sharedData = { a: true, b: "react", c: {} }; class App extends Component { render() { return (); } }
Provider組件模式非常實(shí)用,在react-redux、mobx-react等庫(kù)中,都有使用到這種模式。
React 深入系列文章到此完結(jié),希望能幫助大家更加深入的理解React,更加純熟的應(yīng)用React。
我的新書(shū)《React進(jìn)階之路》已上市,請(qǐng)大家多多支持!
鏈接:京東 當(dāng)當(dāng)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95195.html
摘要:在項(xiàng)目中用好高階組件,可以顯著提高代碼質(zhì)量。高階組件的定義類(lèi)比于高階函數(shù)的定義。高階函數(shù)接收函數(shù)作為參數(shù),并且返回值也是一個(gè)函數(shù)。 React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深對(duì)React的理解,以及在項(xiàng)目中更加靈活地使用React。 1. 基本概念 高階組件是React 中一個(gè)很重要且比較復(fù)雜的概念,高階組件在很多第三方庫(kù)(如Redux)中都...
摘要:系列種優(yōu)化頁(yè)面加載速度的方法隨筆分類(lèi)中個(gè)最重要的技術(shù)點(diǎn)常用整理網(wǎng)頁(yè)性能管理詳解離線緩存簡(jiǎn)介系列編寫(xiě)高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問(wèn)性能優(yōu)化方案實(shí)現(xiàn)的大排序算法一怪對(duì)象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁(yè)面加載速度的方法 隨筆分類(lèi) - HTML5 HTML5中40個(gè)最重要的技術(shù)點(diǎn) 常用meta整理 網(wǎng)頁(yè)性能管理詳解 HTML5 ...
摘要:系列種優(yōu)化頁(yè)面加載速度的方法隨筆分類(lèi)中個(gè)最重要的技術(shù)點(diǎn)常用整理網(wǎng)頁(yè)性能管理詳解離線緩存簡(jiǎn)介系列編寫(xiě)高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問(wèn)性能優(yōu)化方案實(shí)現(xiàn)的大排序算法一怪對(duì)象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁(yè)面加載速度的方法 隨筆分類(lèi) - HTML5 HTML5中40個(gè)最重要的技術(shù)點(diǎn) 常用meta整理 網(wǎng)頁(yè)性能管理詳解 HTML5 ...
摘要:深入之繼承的多種方式和優(yōu)缺點(diǎn)深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。對(duì)于解釋型語(yǔ)言例如來(lái)說(shuō),通過(guò)詞法分析語(yǔ)法分析語(yǔ)法樹(shù),就可以開(kāi)始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn) JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫(xiě)在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...
閱讀 1476·2021-11-22 14:44
閱讀 2851·2021-11-16 11:44
閱讀 3219·2021-10-13 09:40
閱讀 2013·2021-10-08 10:04
閱讀 2374·2021-09-24 10:28
閱讀 2922·2021-09-06 15:02
閱讀 2971·2019-08-30 15:52
閱讀 2410·2019-08-30 13:20