React知識點整理

初入React

JSX語法

  • 定義標(biāo)簽時,只允許被一個標(biāo)簽包裹
  • 標(biāo)簽一定要閉合
  • 注釋被{}包起來

React組件

  • 無狀態(tài)組件創(chuàng)建時始終保持了一個實例
  • 有狀態(tài)組件創(chuàng)建幾次組件就會創(chuàng)建幾次實例

React數(shù)據(jù)流

state
  • setState是異步方法
props
  • props本身是不可變的(readonly
  • defaultProps靜態(tài)變量可以定義props默認(rèn)配置(默認(rèn)類型
static defaultProps = {
    classPrefix: 'tabs', 
    onChange: () => {},
};

  • React中有一個內(nèi)置的prop:children,代表組件的子組件集合
  • JavaScript不是強(qiáng)類型的語言,React對此做了改進(jìn),propTypes用于規(guī)范props的類型與必要狀態(tài)(類型檢查)。
static propTypes = {
  tab: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.node,
  ]).isRequired,
  order: React.PropTypes.string.isRequired,
  disble: React.PropTypes.bool,
};

React生命周期

分為掛載、渲染、卸載幾個階段

掛載或卸載

主要做組件狀態(tài)初始化

掛載
掛載流程
卸載
卸載流程
數(shù)據(jù)更新

指父組件向下傳遞props或組件自身執(zhí)行setState方法時發(fā)生的一系列更新動作

import React, {Component, PropTypes} from 'react';

class App extends Component {
    componentWillReceiveProps(nextProps){
        //this.setState({})
    }

    shouldComponentUpdate(nextProps, nextState) {

    }

    componentWillUpdate(nextProps, nextState) {

    }

    componentDidUpdate(prevProps, prevState) {

    }

    render() {

    }
}

組件自身state更新
組件自身state更新

不能在componentWillUpdate里執(zhí)行setState

父組件更新props而更新
  • 在shouldComponentUpdate之前先執(zhí)行componentWillReceiveProps。
  • 該方法可作為React在props傳入后,渲染之前setState。
componentWillReceiveProps(nextProps) {

}

React與DOM

refs

refs是React組件中特殊的props,可以附加到任何一個組件上。組件被調(diào)用時會新建一個該組件的實例,refs則指向這個實例。

  • refs放在原生DOM組件中可以得到其DOM節(jié)點
  • refs放在React組件中則獲得組件的實例,可以調(diào)用該組件的實例方法

漫談React

事件系統(tǒng)

在React底層,主要對合成事件做了兩件事:事件委派和自動綁定。

在React中使用原生事件

React生命周期方法中,componentDidMount會在組件已經(jīng)完成安裝并且在瀏覽器中存在真實的DOM后調(diào)用,此時可以完成原生事件的綁定。

import React, {Component} from 'react';

class NativeEventDemo extends Component {
    componentDidMound() {
        this.refs.button.addEventListener('click', e => {
            handleClick(e);
        });
    }

    handerClick(e) {
        console.log(e);
    }

    componentWillUnMount() {
        this.refs.button.removeEventListener('click');
    }

    render() {
        return <button ref="button">Test</button>
    }
}

注:在React中使用DOM原生事件時,一定要在組件卸載時手動卸除,否則很可能會出現(xiàn)內(nèi)存泄漏的問題。

對比React合成事件與JavaScript原生事件
  • 瀏覽器原生DOM事件的傳播可以分為三個階段:事件捕獲階段、事件處理以及事件冒泡。React的合成事件并沒有實現(xiàn)事件捕獲,僅僅支持了事件冒泡機(jī)制。阻止事件傳播e.preventDefault();
  • React合成事件的時間類型是JavaScript原生事件類型的一個子集。

組件間通信

父組件向子組件通信

父組件通過props向子組件傳遞需要的信息

import React, {Component} from 'react';

function ListItem({value}) {
    return (
        <li>
            <span>{value}</span>
        </li>
    );
}

function List({list, title}) {
    return(
        <div>
            <ListTitle title={title} />
            <ul>
                {this.props.list.map((entry, index) => {
                    <ListItem key={`list-${index}`} value={entry.text}>

                })}
            </ul>
        </div>
    );
}

子組件向父組件通信
  • 利用回調(diào)函數(shù)
  • 利用自定義事件機(jī)制

this.props.function()

跨級組件通信

組件新能優(yōu)化

影響網(wǎng)頁性能最大的因素是瀏覽器的重繪重排版(回流與重繪?)。

純函數(shù)

純函數(shù)由三大原則構(gòu)成:

  • 給定相同的輸入,返回相同的輸出
  • 過程沒有副作用(在純函數(shù)中不能改變外部狀態(tài))
  • 沒有額外的狀態(tài)依賴(方法內(nèi)的狀態(tài)都只在方法的生命周期內(nèi)存活,即不能再方法內(nèi)使用共享變量)
PureRender

Pure指的是組件滿足純函數(shù)的條件,即組件的渲染是被相同的props和state渲染進(jìn)而得到相同的結(jié)果

Immutable
key
  • 如果每一個子組件是一個數(shù)組或迭代器,必須有一個唯一的key prop
  • key用來做Virtual DOM dif
  • 當(dāng)key相同時,只渲染第一個相同key的項,且會報一個警告

解讀React源碼

Virtual DOM實際上是在瀏覽器端用JavaScript實現(xiàn)的一套DOM API,它之于React就好似一個虛擬空間,包括一套Virtual DOM模型、生命周期的維護(hù)和管理、性能高效的diff算法和將Virtual DOM展示為原生DOM的path方法。

Virtual DOM模型

一個DOM標(biāo)簽所需的基本元素:

  • 標(biāo)簽名
  • 節(jié)點屬性,包含樣式、屬性、事件等
  • 子節(jié)點
  • 標(biāo)識id

Virtual DOM中的節(jié)點稱為ReactNode,它分為三種類型ReactElement、ReactFragment和ReactText。其中,ReactElement又分為ReactComponentElement和ReactDOMElement。

創(chuàng)建React元素
//createElement只是做了簡單的參數(shù)修正,返回一個ReactElement實例對象,也就是虛擬元素的實例
ReactElement.createElement = function(type, config, children){

}

DOM標(biāo)簽組件

ReactDOMComponent針對Virtual DOM標(biāo)簽的處理主要分為:

  • 屬性的更新,包括更新樣式、更新屬性、處理事件等。
  • 子節(jié)點的更新,包括更新內(nèi)容、更新子節(jié)點,涉及diff算法。
更新屬性
  • 如果存在事件,則針對當(dāng)前的節(jié)點添加事件代理
  • 如果存在樣式,首先會對樣式進(jìn)行合并操作,然后創(chuàng)建樣式
  • 創(chuàng)建屬性
  • 創(chuàng)建唯一標(biāo)識

刪除不需要的舊屬性,更新新屬性。

更新子節(jié)點
  • 刪除不需要的子節(jié)點和內(nèi)容
  • 更新子節(jié)點和內(nèi)容

生命周期的管理藝術(shù)

生命周期在不同狀態(tài)下的執(zhí)行順序:

  • 當(dāng)首次掛載時,按順序執(zhí)行getDefaultProps、getInitialState、componentWillMount、render、componentDidMount
  • 當(dāng)卸載組件時,執(zhí)行componentWillUnmount
  • 當(dāng)重新掛載組件時,按順序執(zhí)行getInitialState、componentWillMount、render和componentDidMount,但并不執(zhí)行g(shù)etDefaultProps
  • 當(dāng)再次渲染組件時,組件接受到更新的狀態(tài),此時按順序執(zhí)行componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render和componentDidUpdate。
first render
first render
props change
props change
state change
state change

自定義組件的聲明周期主要通過3個階段進(jìn)行管理:MOUNTING、RECEIVE_PROPS、UNMOUNTING

MOUNTING

mountComponent負(fù)責(zé)管理生命周期中的getInitialState、componentWillMount、render和componentDidMount。

  • getDefault是通過構(gòu)造函數(shù)進(jìn)行管理的,所以也是整個生命周期中最先開始執(zhí)行的,只執(zhí)行一次。
  • 此時在componentWillMount中調(diào)用setState方法不會觸發(fā)re-render,而是會進(jìn)行state合并。
  • mountComponent的本質(zhì)是通過遞歸渲染內(nèi)容,由于遞歸的特性,父組件的componentWillMount在其子組件的componentWillMount之前調(diào)用,父組件的componentDidMount在子組件的componentDidMount之后調(diào)用。
RECEIVE_PROPS

updateComponent負(fù)責(zé)管理生命周期中的componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render和componentDidUpdate。

  • 首先通過updateComponent更新組件,如果前后元素不一致,說明需要進(jìn)行組件更新
  • 此時在componentWillReceiveProps中調(diào)用setState不會觸發(fā)re-render,而是會進(jìn)行state合并
  • 只有在render和componentDidUpdate中才能獲取到更新后的this.state
  • updateComponent本質(zhì)上也是通過遞歸渲染內(nèi)容,父組件的componentWillUpdate是在其子組件的componentWillUpdate之前調(diào)用,父組件的componentDidUpdate子組件的componentDidUpdate之后調(diào)用
UNMOUNTING

unmountComponent負(fù)責(zé)管理生命周期中的componentWilUnmount。

  • 如果存在componentWillUnmount,則執(zhí)行并重置所有相關(guān)參數(shù)、更新隊列以及更新狀態(tài)
  • 此時在componentWillUnmount中調(diào)用setState不會觸發(fā)re-render,因為所有更新隊列和更新狀態(tài)都被重置為null,并清除了公共類,完成了組件卸載操作

解密setState機(jī)制

  • setState通過一個隊列機(jī)制實現(xiàn)state更新
  • 當(dāng)執(zhí)行setState時,會將需要更新的state合并后放入狀態(tài)機(jī),而不會立刻更新this.state
  • 如果在shouldComponentUpdate或componentWillUpdate方法中調(diào)用setState,會造成循環(huán)調(diào)用,使得瀏覽器內(nèi)存占滿后崩潰
setState調(diào)用棧
import React, {component} from 'react';

class Example extends Component {
    constructor() {
        super();
        this.state = {
            val: 0;
        }
    }

    componentDidMount() {
        this.setState({val: this.state.val + 1});
        console.log(this.state.val);

        this.setState({val: this.state.val + 1});
        console.log(this.state.val);

        setTimeout(() => {
            this.setState({val: this.state.val + 1});
            console.log(this.state.val);

            this.setState({val: this.state.val + 1});
            console.log(this.state.val);
        }, 0);
    }

    render() {
        return null;
    }
}

//輸出 0 0 2 3

事務(wù)
  • 事務(wù)就是將需要執(zhí)行的方法使用wrapper封裝起來,再通過事務(wù)提供的perform方法執(zhí)行

diff算法

diff幫助計算出Virtual DOM中真正變化的部分,并只針對該部分進(jìn)行原生DOM操作,而非重新渲染整個頁面

詳解diff
diff策略
  • Web UI中DOM節(jié)點跨層級的移動操作特別少,可以忽略不計
  • 擁有相同類的兩個組件將會生成相似的樹形結(jié)構(gòu),擁有不同類的兩個組件將會生成不同的樹形結(jié)構(gòu)
  • 對于同一層級的一組子節(jié)點,可以通過唯一id進(jìn)行區(qū)分

React分別對tree diff、component diff以及element diff進(jìn)行算法優(yōu)化。

tree diff
  • 對樹進(jìn)行分層比較,兩棵樹只會對同一層次的節(jié)點進(jìn)行比較
  • 當(dāng)發(fā)現(xiàn)節(jié)點已經(jīng)不存在時,則改節(jié)點及其子節(jié)點會被完全刪除掉
component diff
  • 如果是同一類型的組件,按照原策略繼續(xù)比較Virtual DOM樹即可
  • 如果不是,則將改組件判斷為dirty component,從而替換整個組件下的所有子節(jié)點
  • React允許用戶通過shouldComponentUpdate()來判斷該組件是否需要進(jìn)行diff算法分析
element diff
  • INSERT_MARKUP: 新的組件類型不在舊集合里,需對新節(jié)點執(zhí)行插入操作
  • MOVE_EXISTING: 舊集合中有新組件類型,且element是可更新類型,需要做移動操作,可以復(fù)用以前的DOM節(jié)點
  • REMOVE_NODE: 舊組件類型,在新集合里也有,但對應(yīng)的element不同則不能直接復(fù)用和更新,需要執(zhí)行刪除操作,或者舊組件不在新集合里的,也需要執(zhí)行刪除操作

節(jié)點在新集合中的索引值大于在舊集合中的索引時,需移動
刪除操作是移動完成之后遍歷舊集合,若有新集合中未出現(xiàn)的節(jié)點則刪除

React Patch方法

將tree diff計算出來的DOM差異隊列更新到真實的DOM節(jié)點上,讓瀏覽器能夠渲染出更新的數(shù)據(jù)

  • 主要通過遍歷差異隊列實現(xiàn)

認(rèn)識Flux架構(gòu)模式

React獨立架構(gòu)

  • 含有抽象數(shù)據(jù)而沒有業(yè)務(wù)邏輯的組件為容器型組件
  • 沒有數(shù)據(jù)請求邏輯只有業(yè)務(wù)邏輯的組件為展示型組件

MV*與Flux

MVC/MVVM

主要涉及三種角色:Model、View和Controller

  • Model:負(fù)責(zé)保存應(yīng)用數(shù)據(jù),和后端交互同步應(yīng)用數(shù)據(jù),或校驗數(shù)據(jù)
  • View:是Model的可視化表示,表示當(dāng)前狀態(tài)的視圖。前端View負(fù)責(zé)構(gòu)建和維護(hù)DOM元素。
  • Controller:負(fù)責(zé)連接View和Model,Model的任何改變會應(yīng)用到View中,View的操作會通過Controller應(yīng)用到Model中
Flux

核心思想是<mark style="box-sizing: border-box;">數(shù)據(jù)和邏輯永遠(yuǎn)單向流動</mark>。

flux

在Flux應(yīng)用中,數(shù)據(jù)從action到dispatcher再到store,最終到view的路線是單項不可逆的

Flux基本概念

一個Flux應(yīng)用由3大部分組成:dispatcher、store和view,其中dispatcher負(fù)責(zé)分發(fā)事件;store負(fù)責(zé)保存數(shù)據(jù),同時響應(yīng)時間并更新數(shù)據(jù);view負(fù)責(zé)訂閱store中的數(shù)據(jù)。

dispatcher

dispatcher是Flux中最核心的方法,也是flux這個npm包中的核心方法。 只需關(guān)心.register(callback)和.dispatch(action)這兩個API。

  • register方法用來注冊一個監(jiān)聽器
  • dispatch方法用來分發(fā)一個action
action

action是一個普通的JavaScript對象,一般包含type、payload等字段,用于描述一個事件以及需要改變的相關(guān)數(shù)據(jù)。

store
  • 在Flux中,store負(fù)責(zé)保存數(shù)據(jù),并定義修改數(shù)據(jù)的邏輯,同時調(diào)用dispatcher的register方法將自己注冊為一個監(jiān)聽器。
  • 每次使用dispatcher的dispatch方法分發(fā)一個action時,store注冊的監(jiān)聽器會被調(diào)用,同時得到這個action作為參數(shù)。
  • 在Flux中,store對外只暴露getter而不暴露setter,即只能讀取store中的數(shù)據(jù)而不能進(jìn)行任何修改。
controller-view

一般來說,controller-view是整個應(yīng)用最頂層的view,主要進(jìn)行store與React組件之間的綁定,定義數(shù)據(jù)更新以及傳遞的方式

view

如果界面操作需要修改數(shù)據(jù),必須使用dispatcher分發(fā)一個action。

actionCreator

深入Redux應(yīng)用架構(gòu)

Redux簡介

Redux三大原則
單一數(shù)據(jù)源
  • 在Redux的思想里,一個應(yīng)用永遠(yuǎn)只有唯一的數(shù)據(jù)源。
  • 整個應(yīng)用狀態(tài)都保存在一個對象中
狀態(tài)是只讀的

定義一個reducer,其功能是根據(jù)當(dāng)前觸發(fā)的action對當(dāng)前應(yīng)用的狀態(tài)(state)進(jìn)行迭代。沒有直接修改應(yīng)用的狀態(tài),而是返回了一份全新的狀態(tài)。

  • Reducer提供的createStore方法會根據(jù)reducer生成store
  • 用store.dispatch方法來修改狀態(tài)

狀態(tài)修改均由純函數(shù)完成 在Redux里,通過定義reducer來確定狀態(tài)的修改,而每一個reducer都是純函數(shù),即其沒有副作用,接受一定的輸入,必定會得到一定的輸出。

Redux核心API

Redux的核心是一個store,這個store由Redux提供的createStore(reducers[, initialState])方法生成。

  • 在Redux里,負(fù)責(zé)響應(yīng)action并修改數(shù)據(jù)的角色就是reducer
  • reducer在處理action的同時,還需接受一個previousState參數(shù)
  • reducer的職責(zé)是根據(jù)previousState和action計算出新的newState

Redux中最核心的API是createStore,通過createStore方法創(chuàng)建的store是一個對象,包含四個方法:

  • getState():獲取store當(dāng)前狀態(tài)
  • dispatch(action):分發(fā)一個action,并返回這個action,這是<mark style="box-sizing: border-box;">唯一能改變store中數(shù)據(jù)的方式</mark>
  • subscribe(listener):注冊一個監(jiān)聽者,在store發(fā)生變化時調(diào)用
  • replaceReducer(nextReducer):更新當(dāng)前store里的reducer,一般只在開發(fā)模式中調(diào)用該方法

subscribe()和replaceReducer()方法一般會在Redux與某個系統(tǒng)做橋接的時候使用

與React綁定

react-redux提供了一個組件和一個API幫助Redux和React進(jìn)行綁定。

一個是React組件<Provider />,一個是connect()

  • <Provider />接受一個store作為props,它是整個Redux應(yīng)用的頂層組件
  • connect()提供了在整個React應(yīng)用的任意組件中獲取store中數(shù)據(jù)的功能

Redux middleware

middleware的由來
Redux同步數(shù)據(jù)流動
redux同步數(shù)據(jù)流動
應(yīng)用middleware后Redux處理事件的邏輯
應(yīng)用middleware后Redux處理事件的邏輯

每一個middleware處理一個相對獨立的業(yè)務(wù)需求,通過串聯(lián)不同的middleware實現(xiàn)變化多樣的功能

理解middleware機(jī)制

Redux提供了applyMiddleware方法來加載middleware。

import compose from './compose';

export default function applyMiddleware(...middlewares) {
    return (next) => (reducer, initialState) {
        let store = next(reducer, initialState);
        let dispatch = sotre.dispatch;
        let chain = [];

        var middlewareAPI = {
            getState: store.getState,
            dispatch: (action) => dispatch(action),
        };

        chain = middlewares.map(middleware => middleware(middlewareAPI));
        dispatch = compose(...chain)(store.dispatch);

        return {
            ...store,
            dispatch,
        };
    }
}

函數(shù)式編程思想設(shè)計

middleware是一個層層包裹的匿名函數(shù),即函數(shù)式編程中的currying,是一種使用匿名單參數(shù)函數(shù)來實現(xiàn)多參數(shù)的方法。

currying的middleware皆有的好處:

  • 易串聯(lián):currying函數(shù)具有延遲執(zhí)行的特性,通過不斷currying形成的middleware可以累積參數(shù),再配合組合(compose)的方式,很容易形成pipeline來處理數(shù)據(jù)流
  • 共享store:在applyMiddleware執(zhí)行的過程中,store還是舊的,但是因為閉包的存在,applyMiddleware完成后,所有的middleware內(nèi)部拿到的store是最新且相同的。
給middleware分發(fā)store
//創(chuàng)建普通的store
let newStore = applyMiddleware(mid1, mid2, mid3, ...)(createStore)(reducer, null);

組合串聯(lián)middleware
dispatch = compose(...chain)(store.dispatch);

//假設(shè)n=3,dispatch為
dispatch = f1(f2(f3(store.dispatch)));

不能在middleware中調(diào)用dispatch

Redux異步流

Redux與路由

在Redux應(yīng)用中,遇到了一些新的問題,其中最迫切的是,應(yīng)用程序的所有狀態(tài)都應(yīng)該保存在一個單一的store中,而當(dāng)前的路由狀態(tài)很明顯也屬于應(yīng)用狀態(tài)的一部分。如果直接使用React Router,就意味著所有路由相關(guān)的信息脫離了Redux store的控制,這樣就違背了Redux的設(shè)計思想。

React Router
路由的基本原理

理由的基本原理即是保證View和URL同步,而View可以看成是資源的一種表現(xiàn)。

路由的基本原理
React Router特性
  • 在React中,組件就是一個方法,props作為方法的參數(shù),當(dāng)它們發(fā)生變化時觸發(fā)方法執(zhí)行,重繪View
  • 在React Router中,可以把Router組件看成一個方法,location作為參數(shù),返回的結(jié)果同樣是View
聲明式路由
  • React是聲明式編程,所有的交互邏輯都在render返回的JSX標(biāo)簽中得到體現(xiàn)
  • React Router允許使用JSX表現(xiàn)來書寫聲明式的路由
import {Router, Route, browserHistory} from 'react-router';

const routes = (
    <Router history={browserHistory}>
        <Route path="/" component={App} />
    </Router>
);

嵌套路由及路徑匹配
import {Router, Route, IndexRoute, browserHistory} from 'react-router';

const routes = (
    <Router history={browserHistory}>
        <IndexRoute component={MailList} />
        <Route path="/mail/:mailId" component={Mail}></Route>
    </Route>
);

  • 在聲明路由時,path屬性指明了當(dāng)前路由匹配的路徑形式
  • 若某條路由需要參數(shù),只用加上 :參數(shù)名 即可
支持多種路由切換方式

路由切換可以使用hashChange或history.pushState。

  • hashChange擁有良好的瀏覽器兼容性,但是url中多了/#/部分
  • history.pushState能提供優(yōu)雅的url,但需要額外的服務(wù)端配置解決任意路徑刷新的問題

React Router提供了兩種解決方案

<mark style="box-sizing: border-box;">browserHistory即history.pushState的實現(xiàn)</mark>

React Router Redux

職責(zé)主要是將應(yīng)用的路由信息與Redux的store綁定在一起

采用Redux架構(gòu)時,所有的應(yīng)用狀態(tài)都必須放在一個單一的store中管理,路由狀態(tài)也不例外

將React Router與Redux store綁定

React Router Redux提供了簡單直白的API syncHistoryWithStore來完成與Redux store的綁定工作。只需傳入React Router中的history,以及Redux中的store,就可以獲得一個增強(qiáng)后的history對象。

import { browserHistory } from  'react-router';
import { syncHistoryWithState } from 'react-router-redux';
import reducers from '<project-path>/reducers'

const store = createStore(reducers);
const history = syncHistoryWithStore(browserHistory, store);

用Redux的方式改變路由

無論是Flux還是Redux,想要改變數(shù)據(jù),必須要分發(fā)一個action

  • 在此之前,需要對Redux的store進(jìn)行一些增強(qiáng),以便分發(fā)的action能被正確識別
import { browserHistory } from 'react-router';
import { routerMiddleware} from 'react-router-redux';

const middleware = routerMiddleware(browserHistory);
const store = createStore(
    reducers,
    applyMiddleware(middleware)
);

  • 用store.dispatch來分發(fā)一個路由變動的action
import {push} from 'react-router-redux';

store.dispatch(push('/home'));

Redux與組件

容器型組件

容器型組件,意為組件是怎么工作的,具體一些就是數(shù)據(jù)是怎么更新的。不包含任何Virtual DOM的修改或組合,也不會包含組件的樣式。

  • 如果映射到Flux上,容器型組件就是與store綁定的組件
  • 如果映射到Redux上,容器型組件就是使用connect的組件
展示型組件

展示型組件,意為組件是怎么渲染的。包含Virtual DOM的修改和組合,也可能包含組件的樣式。

Redux中的組件
Layouts
  • 指的是頁面布局組件,描述了頁面的基本結(jié)構(gòu),目的是將主框架與頁面主題內(nèi)容分離
  • 常常是無狀態(tài)函數(shù),傳入主題內(nèi)容的children屬性
//一般寫法為
const layout = ({ children }) => (
    <div className='container'>
        <Header />
        <div className='content'>
            { children }
        </div>
    </div>
);

views
  • 指的是子路由入口組件,描述子路由入口的基本結(jié)構(gòu),包含由此路由下所有的展示型組件
  • 為了保持子組件的純凈,在這一層組件中定義了數(shù)據(jù)和action的入口,從這里開始將它們分發(fā)到子組件中去
Components
  • 末級渲染組件,描述了從路由以下的子組件
  • 包含具體的業(yè)務(wù)邏輯和交互
  • 所有的數(shù)據(jù)和action都是由Views傳下來的,即其是可以完全脫離數(shù)據(jù)層而存在的展示型組件
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容