第七章 redux
六、react-redux
7. 代码 - react-redux 数据共享版
7.1 效果
7.2 App
import React, { Component } from "react" ;
import Count from "./containers/Count" ;
import Person from "./containers/Person" ; export default class App extends Component { render ( ) { return ( < div> < Count / > < hr / > < Person / > < / div> ) ; }
}
7.3 Count
import React, { Component } from "react" ;
import { createIncrementAction, createDecrementAction, createIncrementAsyncAction,
} from "../../redux/actions/count" ;
import { connect } from "react-redux" ;
class Count extends Component { increment = ( ) => { const { value } = this . selectNumber; this . props. jia ( value * 1 ) ; } ; decrement = ( ) => { const { value } = this . selectNumber; this . props. jian ( value * 1 ) ; } ; incrementIfOdd = ( ) => { const { value } = this . selectNumber; if ( this . props. count % 2 !== 0 ) { this . props. jia ( value * 1 ) ; } } ; incrementAsync = ( ) => { const { value } = this . selectNumber; this . props. jiaAsync ( value * 1 , 500 ) ; } ; render ( ) { return ( < div> < h2> 我是Count组件,下方组件总人数为:{ this . props. renshu} < / h2> < h4> 当前求和为:{ this . props. count} < / h4> < select ref= { ( c ) => ( this . selectNumber = c) } > < option value= "1" > 1 < / option> < option value= "2" > 2 < / option> < option value= "3" > 3 < / option> < / select> & nbsp; < button onClick= { this . increment} > + < / button> & nbsp; < button onClick= { this . decrement} > - < / button> & nbsp; < button onClick= { this . incrementIfOdd} > 当前求和为奇数再加< / button> & nbsp; < button onClick= { this . incrementAsync} > 异步加< / button> < / div> ) ; }
}
export default connect ( ( state ) => ( { count : state. he, renshu : state. rens. length } ) , { jia : createIncrementAction, jian : createDecrementAction, jiaAsync : createIncrementAsyncAction, }
) ( Count) ;
7.4 Person
import React, { Component } from "react" ;
import { nanoid } from "nanoid" ;
import { connect } from "react-redux" ;
import { createAddPersonAction } from "../../redux/actions/person" ; class Person extends Component { addPerson = ( ) => { const name = this . nameNode. value; const age = this . ageNode. value; const personObj = { id : nanoid ( ) , name, age } ; this . props. jiaYiRen ( personObj) ; this . nameNode. value = "" ; this . ageNode. value = "" ; } ; render ( ) { return ( < div> < h2> 我是Person组件,上方组件求和为{ this . props. he} < / h2> < inputref= { ( c ) => ( this . nameNode = c) } type= "text" placeholder= "输入名字" / > < inputref= { ( c ) => ( this . ageNode = c) } type= "text" placeholder= "输入年龄" / > < button onClick= { this . addPerson} > 添加< / button> < ul> { this . props. yiduiren. map ( ( p ) => { return ( < li key= { p. id} > { p. name} -- { p. age} < / li> ) ; } ) } < / ul> < / div> ) ; }
} export default connect ( ( state ) => ( { yiduiren : state. rens, he : state. he } ) , { jiaYiRen : createAddPersonAction }
) ( Person) ;
7.5 store
import { createStore, applyMiddleware, combineReducers } from "redux" ;
import countReducer from "./reducers/count" ;
import personReducer from "./reducers/person" ;
import thunk from "redux-thunk" ;
const allReducer = combineReducers ( { he : countReducer, rens : personReducer,
} ) ;
export default createStore ( allReducer, applyMiddleware ( thunk) ) ;
7.6 constant
export const INCREMENT = "increment" ;
export const DECREMENT = "decrement" ;
export const ADD_PERSON = "add_person" ;
7.7 actions
7.5.1 count
import { INCREMENT , DECREMENT } from "../constant" ;
export const createIncrementAction = ( data ) => ( { type : INCREMENT , data } ) ;
export const createDecrementAction = ( data ) => ( { type : DECREMENT , data } ) ;
export const createIncrementAsyncAction = ( data, time ) => { return ( dispatch ) => { setTimeout ( ( ) => { dispatch ( createIncrementAction ( data) ) ; } , time) ; } ;
} ;
7.5.2 person
import { ADD_PERSON } from "../constant" ;
export const createAddPersonAction = ( personObj ) => ( { type : ADD_PERSON , data : personObj,
} ) ;
7.8 reducers
7.8.1 count
import { INCREMENT , DECREMENT } from "../constant" ; const initState = 0 ;
export default function countReducer ( preState = initState, action ) { const { type, data } = action; switch ( type) { case INCREMENT : return preState + data; case DECREMENT : return preState - data; default : return preState; }
}
7.8.2 person
import { ADD_PERSON } from "../constant" ;
const initState = [ { id : "001" , name : "tom" , age : 18 } ] ; export default function personReducer ( preState = initState, action ) { const { type, data } = action; switch ( type) { case ADD_PERSON : return [ data, ... preState] ; default : return preState; }
}
7.9 总结
( 1 ) .定义一个Person组件,和Count组件通过redux共享数据。
( 2 ) .为Person组件编写:reducer、action,配置constant常量。
( 3 ) .重点:Person的reducer和Count的Reducer要使用combineReducers进行合并,合并后的总状态是一个对象!!!
( 4 ) .交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。
七、纯函数和高阶函数
1. 纯函数
一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回) 必须遵守以下一些约束 不得改写参数数据 不会产生任何副作用,例如网络请求,输入和输出设备 不能调用 Date.now()或者 Math.random()等不纯的方法 redux 的 reducer 函数必须是一个纯函数
2. 高阶函数
理解: 一类特别的函数 常见的高阶函数: 定时器设置函数 数组的 forEach()/map()/filter()/reduce()/find()/bind() promise react-redux 中的 connect 函数 作用: 能实现更加动态, 更加可扩展的功能
八、使用 redux 调试工具
1. 安装 chrome 浏览器插件
2. 下载工具依赖包
npm install --save-dev redux-devtools-extension
3. 总结
( 1 ) .yarn add redux-devtools-extension
( 2 ) .store中进行配置import { composeWithDevTools} from 'redux-devtools-extension' const store = createStore( allReducer,composeWithDevTools( applyMiddleware( thunk)) )
九、react-redux 最终版
1. index.js
import React from "react" ;
import ReactDOM from "react-dom" ;
import App from "./App" ;
import store from "./redux/store" ;
import { Provider } from "react-redux" ; ReactDOM. render ( < Provider store= { store} > < App / > < / Provider> , document. getElementById ( "root" )
) ;
2. App.jsx
import React, { Component } from "react" ;
import Count from "./containers/Count" ;
import Person from "./containers/Person" ; export default class App extends Component { render ( ) { return ( < div> < Count / > < hr / > < Person / > < / div> ) ; }
}
3. store.js
import { createStore, applyMiddleware } from "redux" ;
import reducer from "./reducers" ;
import thunk from "redux-thunk" ;
export default createStore ( reducer, applyMiddleware ( thunk) ) ;
4. containers
4.1 Count
import React, { Component } from "react" ;
import { increment, decrement, incrementAsync,
} from "../../redux/actions/count" ;
import { connect } from "react-redux" ;
class Count extends Component { increment = ( ) => { const { value } = this . selectNumber; this . props. increment ( value * 1 ) ; } ; decrement = ( ) => { const { value } = this . selectNumber; this . props. decrement ( value * 1 ) ; } ; incrementIfOdd = ( ) => { const { value } = this . selectNumber; if ( this . props. count % 2 !== 0 ) { this . props. increment ( value * 1 ) ; } } ; incrementAsync = ( ) => { const { value } = this . selectNumber; this . props. incrementAsync ( value * 1 , 500 ) ; } ; render ( ) { return ( < div> < h2> 我是Count组件,下方组件总人数为:{ this . props. personCount} < / h2> < h4> 当前求和为:{ this . props. count} < / h4> < select ref= { ( c ) => ( this . selectNumber = c) } > < option value= "1" > 1 < / option> < option value= "2" > 2 < / option> < option value= "3" > 3 < / option> < / select> & nbsp; < button onClick= { this . increment} > + < / button> & nbsp; < button onClick= { this . decrement} > - < / button> & nbsp; < button onClick= { this . incrementIfOdd} > 当前求和为奇数再加< / button> & nbsp; < button onClick= { this . incrementAsync} > 异步加< / button> < / div> ) ; }
}
export default connect ( ( state ) => ( { count : state. count, personCount : state. persons. length, } ) , { increment, decrement, incrementAsync, }
) ( Count) ;
4.2 Person
import React, { Component } from "react" ;
import { nanoid } from "nanoid" ;
import { connect } from "react-redux" ;
import { addPerson } from "../../redux/actions/person" ; class Person extends Component { addPerson = ( ) => { const name = this . nameNode. value; const age = this . ageNode. value * 1 ; const personObj = { id : nanoid ( ) , name, age } ; this . props. addPerson ( personObj) ; this . nameNode. value = "" ; this . ageNode. value = "" ; } ; render ( ) { return ( < div> < h2> 我是Person组件,上方组件求和为{ this . props. count} < / h2> < inputref= { ( c ) => ( this . nameNode = c) } type= "text" placeholder= "输入名字" / > < inputref= { ( c ) => ( this . ageNode = c) } type= "text" placeholder= "输入年龄" / > < button onClick= { this . addPerson} > 添加< / button> < ul> { this . props. personArr. map ( ( p ) => { return ( < li key= { p. id} > { p. name} -- { p. age} < / li> ) ; } ) } < / ul> < / div> ) ; }
} export default connect ( ( state ) => ( { personArr : state. persons, count : state. count, } ) , { addPerson }
) ( Person) ;
5. reducers
5.1 index
import { combineReducers } from "redux" ;
import count from "./count" ;
import persons from "./person" ;
export default combineReducers ( { count, persons
} ) ;
5.2 count
import { INCREMENT , DECREMENT } from "../constant" ; const initState = 0 ;
export default function countReducer ( preState = initState, action ) { const { type, data } = action; switch ( type) { case INCREMENT : return preState + data; case DECREMENT : return preState - data; default : return preState; }
}
5.3 person
import { ADD_PERSON } from "../constant" ;
const initState = [ { id : "001" , name : "tom" , age : 18 } ] ; export default function personReducer ( preState = initState, action ) { const { type, data } = action; switch ( type) { case ADD_PERSON : return [ data, ... preState] ; default : return preState; }
}
6. actions
6.1 count
import { INCREMENT , DECREMENT } from "../constant" ;
export const increment = ( data ) => ( { type : INCREMENT , data } ) ;
export const decrement = ( data ) => ( { type : DECREMENT , data } ) ;
export const incrementAsync = ( data, time ) => { return ( dispatch ) => { setTimeout ( ( ) => { dispatch ( increment ( data) ) ; } , time) ; } ;
} ;
6.2 person
import { ADD_PERSON } from "../constant" ;
export const addPerson = ( personObj ) => ( { type : ADD_PERSON , data : personObj,
} ) ;
7. 总结
( 1 ) .所有变量名字要规范,尽量触发对象的简写形式。
( 2 ) .reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer
十、项目打包
npm run buildnpm install -g serve
serve -s build