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