摘要:手挽手帶你學(xué)入門(mén)四檔用人話教你,理解架構(gòu),以及運(yùn)用在中。學(xué)完這一章,你就可以開(kāi)始自己的項(xiàng)目了。結(jié)合搭建基礎(chǔ)環(huán)境我們上一章講過(guò)了的原理,內(nèi)部是有一個(gè)的,只有才可以控制它變化。
手挽手帶你學(xué)React入門(mén)四檔,用人話教你react-redux,理解redux架構(gòu),以及運(yùn)用在react中。學(xué)完這一章,你就可以開(kāi)始自己的react項(xiàng)目了。
視頻教程上一篇我們自己實(shí)現(xiàn)了Redux,這一篇我們來(lái)看看如何去實(shí)現(xiàn)一個(gè)react-redux
開(kāi)始之前本文需要用到的知識(shí)
首先你要會(huì)React的基礎(chǔ)(這是廢話)react結(jié)合redux 搭建基礎(chǔ)環(huán)境
高階組件
React context
滿足這三項(xiàng)我們開(kāi)始往下看。
我們上一章講過(guò)了redux的原理,內(nèi)部是有一個(gè)store的,store只有dispatch才可以控制它變化。還有在文章一開(kāi)始我們講了React context 可以跨組件傳遞數(shù)據(jù),那么到現(xiàn)在你想到把我們的store掛到最外層一個(gè)組件的context上了嗎?話不多說(shuō) 開(kāi)始!
我們先修改一下我們的react文件(注意不是redux.html這個(gè)文件了)
// App.js import React,{Component} from "react" import PropTypes from "prop-types" //引入 export default class App extends Component { constructor(){ super() this.state={ } } componentWillMount(){ // console.log(hashHistory) } render() { return (創(chuàng)建基本store) } } // 為了展示效果定義子組件一 class Children extends Component{ constructor(){ super() this.state={ } } render(){ return( ) } } // 為了展示效果定義子組件二 ChildrenTwo 是 Children的子組件 但是卻通過(guò)context拿到了App組件拿過(guò)來(lái)的值 (越級(jí)傳遞) class ChildrenTwo extends Component{ constructor(){ super() this.state={ } } render(){ return(我是腦袋
我是身體
) } }
現(xiàn)在我們做好了示例文件的基礎(chǔ)模板了,然后我們需要?jiǎng)?chuàng)建一個(gè)store.js
// store.js // 這是我們的 reducer const changeDom = (state,action) => { if(!state)return{ text : "我是實(shí)例文字", color : "red" } switch(action.type){ case "CHANGE_TEXT": return{ ...state, text:action.text } case "CHANGE_COLOR": return{ ...state, color:action.color } default: return state } } const creatStore = (reducer)=>{ let state = null const listeners = [] const subscribe = (liestner)=>listeners.push(liestner) const getState = ()=>state const dispatch=(action)=>{ state = reducer(state,action) listeners.map(item=>item()) } dispatch({}) return { getState, dispatch, subscribe } } export {creatStore,changeDom}結(jié)合context使用store
我們現(xiàn)在把我們的子組件通過(guò)context公用App的store,并且把渲染方法和dispatch應(yīng)用進(jìn)去
// App.js import React,{Component} from "react" import PropTypes from "prop-types" //引入 // 引入 store import {changeDom,creatStore} from "./store" const store = creatStore(changeDom) export default class App extends Component { // 我們?cè)谶@里把store掛到context上 static childContextTypes = { store: PropTypes.object } getChildContext(){ return{store} } constructor(){ super() this.state={ } } componentWillMount(){ // console.log(hashHistory) } render() { return () } } // 這里我們?cè)偃バ薷奈覀兊淖訉O組建 讓他們可以拿到 store // 為了展示效果定義子組件一 class Children extends Component{ static contextTypes = { store: PropTypes.object } constructor(){ super() this.state={ color:"", text:"" } } // 這里我們定義兩個(gè)渲染方法 getColor(){ let store = this.context.store.getState() this.setState({color:store.color}) } // 這里我們定義兩個(gè)渲染方法 getText(){ let store = this.context.store.getState() this.setState({text:store.text}) } // 這里組件加載之前渲染 componentWillMount(){ this.getColor() this.getText() } render(){ return( ) } } // 為了展示效果定義子組件二 ChildrenTwo 是 Children的子組件 但是卻通過(guò)context拿到了App組件拿過(guò)來(lái)的值 (越級(jí)傳遞) class ChildrenTwo extends Component{ static contextTypes = { store: PropTypes.object } constructor(){ super() this.state={ } } // 這里我們定義 兩個(gè) action changeColor=()=>{ this.context.store.dispatch({type:"CHANGE_COLOR",color:"green"}) console.log(this.context.store.getState()) } changeText=()=>{ this.context.store.dispatch({type:"CHANGE_TEXT",text:"我變了"}) console.log(this.context.store.getState()) //這里方便大家看到數(shù)據(jù)變了 } render(){ return({this.state.text}
) } }
顯然 現(xiàn)在我們點(diǎn)擊按鈕的時(shí)候,并沒(méi)有發(fā)生任何事情,可是我們看console可以看到,store的數(shù)據(jù)確實(shí)變化了,這是為什么呢?很簡(jiǎn)單 我們沒(méi)有把dom監(jiān)聽(tīng)放進(jìn)來(lái),下一步我們要設(shè)置監(jiān)聽(tīng)。
設(shè)置dom監(jiān)聽(tīng)// Children組件 我們?cè)赾omponentWillMount 中添加監(jiān)聽(tīng) class Children extends Component{ static contextTypes = { store: PropTypes.object } constructor(){ super() this.state={ color:"", text:"" } } // 這里我們定義兩個(gè)渲染方法 getColor(){ let store = this.context.store.getState() this.setState({color:store.color}) } // 這里我們定義兩個(gè)渲染方法 getText(){ let store = this.context.store.getState() this.setState({text:store.text}) } // 這里組件加載之前渲染 componentWillMount(){ this.getColor() this.getText() this.context.store.subscribe(()=>{this.getColor()}) this.context.store.subscribe(()=>{this.getText()})// 使用箭頭函數(shù) 保證this指向 } render(){ return() } }{this.state.text}
到這里我們已經(jīng)簡(jiǎn)單地實(shí)現(xiàn)了react-redux,可是大家有沒(méi)有覺(jué)得怪怪的?
開(kāi)始創(chuàng)建connect沒(méi)錯(cuò) 到這里我們頻繁使用context,并且每個(gè)組件都要去手動(dòng)掛context 這是相當(dāng)麻煩的,現(xiàn)在我們想要讓這些東西都自動(dòng)包裹 自動(dòng)生成,我們?cè)僭趺醋瞿亍?br>我們創(chuàng)建一個(gè)高階組件就可以搞定這個(gè)問(wèn)題了(一個(gè)函數(shù),接收一個(gè)組件,生成另外一個(gè)包裝好的新組件)
import React, { Component } from "react" import PropTypes from "prop-types" export const connect = (WrappedComponent)=>{ class Connect extends Component{ static contextTypes = { store: PropTypes.object } render(){ return} } return Connect }
我們這里通過(guò) connect函數(shù)來(lái)接收一個(gè)組件 經(jīng)過(guò)一層封裝 返回一個(gè)包裝了context的組件 但是現(xiàn)在這樣的話 我們每次使用都還需要大量的書(shū)寫(xiě) this.context 是不是相當(dāng)惡心呢? 并且每個(gè)組件都拿到了store 有很多事它并不需要的,這時(shí)候我們就需要告訴這個(gè)高階組件,我這里就只需要這些東西。這就是 mapStateToProps
import React, { Component } from "react" import PropTypes from "prop-types" // 示例 這里不用 // const mapStateToProps=(state)=>{ // return{ // color:state.color, // text:state.text, // } // } 就是我們需要從store拿出來(lái)的東西 const connect= (mapStateToProps) => (WrappedComponent)=>{ class Connect extends Component{ static contextTypes = { store: PropTypes.object } render(){ const store = this.context.stote let stateProps = mapStateToProps(store.getState()) 然后我們把stateProps用...展開(kāi) return} } return Connect }
現(xiàn)在我們利用Connect改造我們的組件
// App.js import React,{Component} from "react" import PropTypes from "prop-types" //引入 // 引入 store import {changeDom,creatStore} from "./store" const store = creatStore(changeDom) // ________________________________把connect_____________________________寫(xiě)在app.js 為的是不引入了 實(shí)際上它是多帶帶拆分在react-redux中的 const connect = (mapStateToProps) => (WrappedComponent)=>{ class Connect extends Component{ static contextTypes = { store: PropTypes.object } render(){ const store = this.context.store console.log(store) let stateProps = mapStateToProps(store.getState()) // 然后我們把stateProps用...展開(kāi) return} } return Connect } // ________________________________把connect_____________________________寫(xiě)在app.js 為的是不引入了 實(shí)際上它是多帶帶拆分在react-redux中的 // app.js 的其他內(nèi)容... // ________________________________對(duì)組件一進(jìn)行修改_____________________________ class Children extends Component{ constructor(){ super() this.state={ color:"", text:"" } } render(){ return( ) } } const mapStateToProps = (state) => { return { color: state.color, text:state.text } } Children = connect(mapStateToProps)(Children) // ________________________________對(duì)組件一進(jìn)行修改_____________________________{this.props.text}
現(xiàn)在我們成功把store里面的所有東西都掛到了props上面,我們不需要去依賴context,只需要調(diào)用props即可。剩下的就是我們的數(shù)據(jù)變更,渲染還有監(jiān)聽(tīng)了!
對(duì) connect 進(jìn)一步改造 其實(shí)就是像我們上面的組件一樣 掛載監(jiān)聽(tīng)
const connect = (mapStateToProps) => (WrappedComponent)=>{ class Connect extends Component{ static contextTypes = { store: PropTypes.object } componentWillMount(){ const{store} = this.context this.updata() store.subscribe(()=>this.updata()) } updata=()=>{ const { store } = this.context let stateProps = mapStateToProps(store.getState(), this.props) this.setState({ allProps: { // 整合普通的 props 和從 state 生成的 props ...stateProps, ...this.props } }) } render(){ // 然后我們把a(bǔ)llProps用...展開(kāi) returnmapDispatchToProps} } return Connect }
state我們改造完了,dispatch 是不是也要一起改造呢?答案是肯定的,mapDispatchToProps就是做這個(gè)的。
我們看看 mapDispatchToProps 是怎么寫(xiě)的 我們倒著推
//const mapDispatchToProps = (dispatch) => { // 傳入的是 dispatch // return { //返回一個(gè)函數(shù) // changeColor: (color) => { // dispatch({ type: "CHANGE_COLOR", color: color }) // } // } //} const connect = (mapStateToProps,mapDispatchToProps) => (WrappedComponent)=>{ class Connect extends Component{ static contextTypes = { store: PropTypes.object } componentWillMount(){ const{store} = this.context this.updata() console.log(store) store.subscribe(()=>this.updata()) } updata=()=>{ const { store } = this.context let stateProps = mapStateToProps?mapStateToProps(store.getState(), this.props):{} let dispatchProps = mapDispatchToProps?mapDispatchToProps(store.dispatch,this.props):{} // 我們要考慮到空值處理 this.setState({ allProps: { // 整合普通的 props 和從 state 生成的 props ...stateProps, ...this.props ...dispatchProps, } }) } render(){ // 然后我們把a(bǔ)llProps用...展開(kāi) return} } return Connect }
到這里我們可以把ChildrenTwo的代碼也改造了
class ChildrenTwo extends Component{ constructor(){ super() this.state={ } } render(){ console.log(this.props) return() } } const mapDispatchToProps = (dispatch)=>{ return { //返回一個(gè)函數(shù) changeColor: (color) => { dispatch({ type: "CHANGE_COLOR", color: color }) }, changeText:(text)=>{ dispatch({ type: "CHANGE_TEXT", text: text }) } } } ChildrenTwo = connect(null,mapDispatchToProps)(ChildrenTwo)
到現(xiàn)在 一個(gè)簡(jiǎn)單的 react-redux已經(jīng)差不多了,但是react-redux里面還有一個(gè)
export class Provider extends Component{ static childContextTypes = { store: PropTypes.object } getChildContext(){ return{store} } render() { return ({this.props.children}) } }
于是 我們現(xiàn)在的代碼變成了這樣
好了 道理講完了 我們現(xiàn)在開(kāi)始拆分代碼啦。
// store.js export const creatStore = (reducer)=>{ let state = null const listeners = [] const subscribe = (liestner)=>listeners.push(liestner) const getState = ()=>state const dispatch=(action)=>{ state = reducer(state,action) listeners.map(item=>item()) } dispatch({}) return { getState, dispatch, subscribe } }
// reducer.js // 這是我們的 reducer 可以多帶帶拆分成一個(gè)js文件 自己拆吧 export const changeDom = (state,action) => { if(!state)return{ text : "我是實(shí)例文字", color : "red" } switch(action.type){ case "CHANGE_TEXT": return{ ...state, text:action.text } case "CHANGE_COLOR": return{ ...state, color:action.color } default: return state } }
// react-redux.js import React,{Component} from "react" import PropTypes from "prop-types" //引入 export const connect = (mapStateToProps,mapDispatchToProps) => (WrappedComponent)=>{ class Connect extends Component{ static contextTypes = { store: PropTypes.object } componentWillMount(){ const{store} = this.context this.updata() store.subscribe(()=>this.updata()) } updata=()=>{ const { store } = this.context let stateProps = mapStateToProps?mapStateToProps(store.getState(), this.props):{} let dispatchProps = mapDispatchToProps?mapDispatchToProps(store.dispatch,this.props):{} // 做一下空值處理 this.setState({ allProps: { // 整合普通的 props 和從 state 生成的 props ...stateProps, ...this.props, ...dispatchProps, } }) } render(){ // 然后我們把a(bǔ)llProps用...展開(kāi) return} } return Connect } export class Provider extends Component{ static childContextTypes = { store: PropTypes.object } getChildContext(){ return {store:this.props.store} } render() { return ( {this.props.children}) } }
// App.js import React,{Component} from "react" import Children from "./Children" import ChildrenTwo from "./ChildrenTwo" export default class App extends Component { constructor(){ super() this.state={ } } render() { return () } }
// Children.js import React,{Component} from "react" import{connect} from "./react-redux.js" class Children extends Component{ constructor(){ super() this.state={ color:"", text:"" } } render(){ return() } } const mapStateToProps = (state) => { return { color: state.color, text:state.text } } Children = connect(mapStateToProps)(Children) export default Children{this.props.text}
// ChildrenTwo.js import React,{Component} from "react" import{connect} from "./react-redux.js" class ChildrenTwo extends Component{ constructor(){ super() this.state={ } } render(){ return() } } const mapDispatchToProps = (dispatch)=>{ return { //返回一個(gè)函數(shù) changeColor: (color) => { dispatch({ type: "CHANGE_COLOR", color: color }) }, changeText:(text)=>{ dispatch({ type: "CHANGE_TEXT", text: text }) } } } ChildrenTwo = connect(null,mapDispatchToProps)(ChildrenTwo) export default ChildrenTwo
拆完了的代碼是不是簡(jiǎn)單明了
真正工作里面 我們需要多做兩步
npm i redux --save npm i react-redux --save
然后 我們
對(duì)照著修改這幾個(gè)位置
// creatStore 在 redux 插件中 // connect,Provider 在 react-redux 插件中 // 也就是用到哪里了 對(duì)應(yīng)修改哪里 改完了你就發(fā)現(xiàn)了新大陸了 import { createStore } from "redux" import { connect,Provider } from "react-redux"
不知不覺(jué)發(fā)現(xiàn)自己不僅僅會(huì)用了react-redux 并且還自己實(shí)現(xiàn)了一個(gè)react-redux 很舒坦的呢
總結(jié)在我們四檔下篇到這里結(jié)束了,這就是react-redux的實(shí)現(xiàn)和寫(xiě)法,大家自己去實(shí)現(xiàn)真正的寫(xiě)法,這里不做演示相當(dāng)于給大家留個(gè)作業(yè),有錯(cuò)誤或者是有建議 或者有不懂的地方 掃碼加我微信給大家解答。
視頻制作中文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/101641.html
手挽手帶你學(xué)React入門(mén)四檔,用人話教你react-redux,理解redux架構(gòu),以及運(yùn)用在react中。學(xué)完這一章,你就可以開(kāi)始自己的react項(xiàng)目了。 之前在思否看到過(guò)某個(gè)大神的redux搭建 忘記了大神的名字 這里只記得內(nèi)容了 憑借記憶和當(dāng)時(shí)的學(xué)習(xí)路線寫(xiě)下本文 隔空感謝 本人學(xué)習(xí)react-redux的時(shí)候遇到了很多坎,特別是不理解為什么這么用,這是什么東西,用來(lái)做什么。加上各種名詞讓人...
摘要:當(dāng)屬性是一個(gè)回調(diào)函數(shù)時(shí),函數(shù)接收底層元素或類實(shí)例取決于元素的類型作為參數(shù)。 手挽手帶你學(xué)React入門(mén)第一期,帶你熟悉React的語(yǔ)法規(guī)則,消除對(duì)JSX的恐懼感,由于現(xiàn)在開(kāi)發(fā)中都是使用ES6語(yǔ)法開(kāi)發(fā)React,所以這次也使用ES6的模式進(jìn)行教學(xué),如果大家對(duì)ES6不熟悉的話,先去看看class相關(guān)內(nèi)容吧,這里我也慢慢帶大家一步一步學(xué)會(huì)React。 視頻教程 視頻教程可移步我的個(gè)人博客:h...
摘要:這樣,我們用寫(xiě)的就寫(xiě)好了。真的假的大家可以看到,這些在插值表達(dá)式內(nèi)的表達(dá)式直接返回了運(yùn)行完成的結(jié)果,值得一提的是,差值表達(dá)式內(nèi)的規(guī)則和標(biāo)簽內(nèi)的規(guī)則是類似的。 視頻教程 由于思否不能插入視頻,視頻請(qǐng)大家移步,http://www.henrongyi.top 什么是VUE VUE是一套用于構(gòu)建用戶界面的漸進(jìn)式框架,VUE并不是一個(gè)真正意義上的mvvm框架,它更傾向是一種數(shù)據(jù)驅(qū)動(dòng)框架.所以我...
摘要:這樣,我們用寫(xiě)的就寫(xiě)好了。真的假的大家可以看到,這些在插值表達(dá)式內(nèi)的表達(dá)式直接返回了運(yùn)行完成的結(jié)果,值得一提的是,差值表達(dá)式內(nèi)的規(guī)則和標(biāo)簽內(nèi)的規(guī)則是類似的。 視頻教程 由于思否不能插入視頻,視頻請(qǐng)大家移步,http://www.henrongyi.top 什么是VUE VUE是一套用于構(gòu)建用戶界面的漸進(jìn)式框架,VUE并不是一個(gè)真正意義上的mvvm框架,它更傾向是一種數(shù)據(jù)驅(qū)動(dòng)框架.所以我...
摘要:安裝過(guò)后到命令行執(zhí)行檢查版本,如果彈出版本的話恭喜你安裝成功,我們開(kāi)始進(jìn)行下面的步驟了。全局安裝的包名稱由改成了。如果你已經(jīng)全局安裝了舊版本的或,你需要先通過(guò)卸載它。中的非常類似于事件每個(gè)都有一個(gè)字符串的事件類型和一個(gè)回調(diào)函數(shù)。 視頻教程 由于思否不支持視頻外鏈,視頻請(qǐng)移步http://www.henrongyi.top 你能學(xué)到什么 在這一期的學(xué)習(xí)進(jìn)度中,我們會(huì)開(kāi)始學(xué)習(xí)在我們工作開(kāi)...
閱讀 1110·2021-09-22 16:04
閱讀 1494·2019-08-30 15:43
閱讀 1096·2019-08-29 14:01
閱讀 3437·2019-08-26 12:19
閱讀 3351·2019-08-26 12:15
閱讀 1443·2019-08-26 12:13
閱讀 3263·2019-08-23 17:00
閱讀 1482·2019-08-23 15:38