第七章 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>
< input
ref= { ( c ) => ( this . nameNode = c) }
type= "text"
placeholder= "输入名字"
/ >
< input
ref= { ( 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>
< input
ref= { ( c ) => ( this . nameNode = c) }
type= "text"
placeholder= "输入名字"
/ >
< input
ref= { ( 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 build
npm install -g serve
serve -s build