摘要:本篇是深入系列的最后一篇,將介紹開發應用時,經常用到的模式,這些模式并非都有官方名稱,所以有些模式的命名并不一定準確,請讀者主要關注模式的內容。
React 深入系列,深入講解了React中的重點概念、特性和模式等,旨在幫助大家加深對React的理解,以及在項目中更加靈活地使用React。
本篇是React深入系列的最后一篇,將介紹開發React應用時,經常用到的模式,這些模式并非都有官方名稱,所以有些模式的命名并不一定準確,請讀者主要關注模式的內容。
1. 受控組件React 組件的數據流是由state和props驅動的,但對于input、textarea、select等表單元素,因為可以直接接收用戶在界面上的輸入,所以破壞了React中的固有數據流。為了解決這個問題,React引入了受控組件,受控組件指input等表單元素顯示的值,仍然是通過組件的state獲取的,而不是直接顯示用戶在界面上的輸入信息。
受控組件的實現:通過監聽表單元素值的變化,改變組件state,根據state顯示組件最終要展示的值。一個簡單的例子如下:
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 (); } }
和受控組件對應的概念是非受控組件,非受控組件通過ref獲取表單元素的值,在一些場景下有著特有的作用(如設置表單元素的焦點)。
2. 容器組件容器組件和展示組件是一組對應的概念,關注的是組件邏輯和組件展示的分離。邏輯由容器組件負責,展示組件聚焦在視圖層的展現上。在React 深入系列2:組件分類中已對容器組件和展示組件作過詳細介紹,這里不再贅述。
3. 高階組件高階組件是一種特殊的函數,接收組件作為輸入,輸出一個新的組件。高階組件的主要作用是封裝組件的通用邏輯,實現邏輯的復用。在React 深入系列6:高階組件中已經詳細介紹過高階組件,這里也不再贅述。
4. Children傳遞首先,這個模式的命名可能并不恰當。這個模式中,借助React 組件的children屬性,實現組件間的解耦。常用在一個組件負責UI的框架,框架內部的組件可以靈活替換的場景。
一個示例:
// ModalDialog.js export default function ModalDialog({ children }) { return{ children }; }; // App.js render() {}
ModalDialog組件是UI的框,框內組件可以靈活替換。
5. Render PropsRender Props是把組件部分的渲染邏輯封裝到一個函數中,利用組件的props接收這個函數,然后在組件內部調用這個函數,執行封裝的渲染邏輯。
看一個官方的例子:
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組件并不知道應該如何渲染這部分內容, * 這部分渲染邏輯是通過props的render屬性傳遞給Mouse組件 */} {this.props.render(this.state)}); } } class MouseTracker extends React.Component { render() { return (); } }Move the mouse around!
( )}/>
Mouse監聽鼠標的移動,并將鼠標位置保存到state中。但Mouse組件并不知道最終要渲染出的內容,需要調用this.props.render方法,執行渲染邏輯。本例中,Cat組件會渲染到鼠標移動到的位置,但完全可以使用其他效果來跟隨鼠標的移動,只需更改render方法即可。由此可見,Mouse組件只關注鼠標位置的移動,而跟隨鼠標移動的界面效果,由使用Mouse的組件決定。這是一種基于切面編程的思想(了解后端開發的同學應該比較熟悉)。
使用這種模式,一般習慣將封裝渲染邏輯的函數賦值給一個命名為render的組件屬性(如本例所示),但這并不是必需,你也可以使用其他的屬性命名。
這種模式的變種形式是,直接使用React組件自帶的children屬性傳遞。上面的例子改寫為:
class Mouse extends React.Component { // 省略 render() { return ({/* * Mouse組件并不知道應該如何渲染這部分內容, * 這部分渲染邏輯是通過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 這兩個庫都使用到了Render Props模式。很多場景下,Render Props實現的功能也可以通過高階組件實現。本例也可以用高階組件實現,請讀者自行思考。
6. Provider組件這種模式借助React的context,把組件需要使用的數據保存到context,并提供一個高階組件從context中獲取數據。
一個例子:
先創建MyProvider,將共享數據保存到它的context中,MyProvider一般作為最頂層的組件使用,從而確保其他組件都能獲取到context中的數據:
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中的數據從props中獲取 return { sharedData: this.props.sharedData }; } render() { return this.props.children; } }
然后創建高階組件connectData,用于從context中獲取所需數據:
export const connectData = WrappedComponent => class extends React.Component { static contextTypes = contextTypes; render() { const { props, context } = this; return; } };
最后在應用中使用:
const SomeComponentWithData = connectData(SomeComponent) const sharedData = { a: true, b: "react", c: {} }; class App extends Component { render() { return (); } }
Provider組件模式非常實用,在react-redux、mobx-react等庫中,都有使用到這種模式。
React 深入系列文章到此完結,希望能幫助大家更加深入的理解React,更加純熟的應用React。
我的新書《React進階之路》已上市,請大家多多支持!
鏈接:京東 當當
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95195.html
摘要:在項目中用好高階組件,可以顯著提高代碼質量。高階組件的定義類比于高階函數的定義。高階函數接收函數作為參數,并且返回值也是一個函數。 React 深入系列,深入講解了React中的重點概念、特性和模式等,旨在幫助大家加深對React的理解,以及在項目中更加靈活地使用React。 1. 基本概念 高階組件是React 中一個很重要且比較復雜的概念,高階組件在很多第三方庫(如Redux)中都...
摘要:深入之繼承的多種方式和優缺點深入系列第十五篇,講解各種繼承方式和優缺點。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執行了。 JavaScript深入之繼承的多種方式和優缺點 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優缺點。 寫在前面 本文講解JavaScript各種繼承方式和優缺點。 但是注意: 這篇文章更像是筆記,哎,再讓我...
閱讀 1473·2021-11-22 14:44
閱讀 2850·2021-11-16 11:44
閱讀 3218·2021-10-13 09:40
閱讀 2002·2021-10-08 10:04
閱讀 2373·2021-09-24 10:28
閱讀 2920·2021-09-06 15:02
閱讀 2969·2019-08-30 15:52
閱讀 2406·2019-08-30 13:20