一、基本使用
(1).明确两个概念:
1).UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
2).容器组件:负责和redux通信,将结果交给UI组件。
(2).如何创建一个容器组件————靠react-redux 的 connect函数
connect(mapStateToProps,mapDispatchToProps)(UI组件)
-mapStateToProps:映射状态,返回值是一个对象
-mapDispatchToProps:映射操作状态的方法,返回值是一个对象
(3).备注1:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入
(4).备注2:mapDispatchToProps,也可以是一个对象
(5).安装:npm install react-redux
二、优化
(1).容器组件和UI组件整合一个文件
(2).无需自己给容器组件传递store,给<App/>包裹一个<Provider store={store}>即可。
(3).使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。
(4).mapDispatchToProps也可以简单的写成一个对象
(5).一个组件要和redux“打交道”要经过哪几步?
(1).定义好UI组件---不暴露
(2).引入connect生成一个容器组件,并暴露,写法如下:
connect(
state => ({key:value}), //映射状态
{key:xxxxxAction} //映射操作状态的方法
)(UI组件)
(4).在UI组件中通过this.props.xxxxxxx读取和操作状态
三、数据共享
(1).定义一个Pserson组件,和Count组件通过redux共享数据。
(2).为Person组件编写:reducer、action,配置constant常量。
(3).重点:Person的reducer和Count的Reducer要使用combineReducers进行合并,
合并后的总状态是一个对象!!!
(4).交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。
四、react-redux开发者工具的使用
(1).npm install redux-devtools-extension
(2).store中进行配置
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
五、代码
1. App.jsx
代码语言:javascript复制 1 import React, { Component } from 'react'
2 import Count from './containers/Count' //引入的Count的容器组件
3 import Person from './containers/Person' //引入的Person的容器组件
4
5 export default class App extends Component {
6 render() {
7 return (
8 <div>
9 <Count/>
10 <hr/>
11 <Person/>
12 </div>
13 )
14 }
15 }
2. index.js
代码语言:javascript复制 1 import React from 'react'
2 import ReactDOM from 'react-dom'
3 import App from './App'
4 import store from './redux/store'
5 import {Provider} from 'react-redux'
6
7 ReactDOM.render(
8 /* 此处需要用Provider包裹App,目的是让App所有的后代容器组件都能接收到store */
9 <Provider store={store}>
10 <App/>
11 </Provider>,
12 document.getElementById('root')
13 )
3.redux/store.js
代码语言:javascript复制 1 /*
2 该文件专门用于暴露一个store对象,整个应用只有一个store对象
3 */
4
5 //引入createStore,专门用于创建redux中最为核心的store对象
6 import {createStore,applyMiddleware} from 'redux'
7 //引入汇总之后的reducer
8 import reducer from './reducers'
9 //引入redux-thunk,用于支持异步action
10 import thunk from 'redux-thunk'
11 //引入redux-devtools-extension
12 import {composeWithDevTools} from 'redux-devtools-extension'
13
14 //暴露store
15 export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))
4.constant.js
代码语言:javascript复制1 /*
2 该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
3 */
4 export const INCREMENT = 'increment'
5 export const DECREMENT = 'decrement'
6 export const ADD_PERSON = 'add_person'
5.redux/reducers/index.js
代码语言:javascript复制 1 /*
2 该文件用于汇总所有的reducer为一个总的reducer
3 */
4 //引入combineReducers,用于汇总多个reducer
5 import {combineReducers} from 'redux'
6 //引入为Count组件服务的reducer
7 import count from './count'
8 //引入为Person组件服务的reducer
9 import persons from './person'
10
11 //汇总所有的reducer变为一个总的reducer
12 export default combineReducers({
13 count,
14 persons
15 })
6.redux/reducers/count.js
代码语言:javascript复制 1 /*
2 1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
3 2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
4 */
5 import {INCREMENT,DECREMENT} from '../constant'
6
7 const initState = 0 //初始化状态
8 export default function countReducer(preState=initState,action){
9 // console.log('countReducer@#@#@#');
10 //从action对象中获取:type、data
11 const {type,data} = action
12 //根据type决定如何加工数据
13 switch (type) {
14 case INCREMENT: //如果是加
15 return preState data
16 case DECREMENT: //若果是减
17 return preState - data
18 default:
19 return preState
20 }
21 }
7.redux/reducers/person.js
代码语言:javascript复制 1 import {ADD_PERSON} from '../constant'
2
3 //初始化人的列表
4 const initState = [{id:'001',name:'tom',age:18}]
5
6 export default function personReducer(preState=initState,action){
7 // console.log('personReducer@#@#@#');
8 const {type,data} = action
9 switch (type) {
10 case ADD_PERSON: //若是添加一个人
11 //preState.unshift(data) //此处不可以这样写,这样会导致preState被改写了,personReducer就不是纯函数了。
12 return [data,...preState]
13 default:
14 return preState
15 }
16 }
8.redux/actions/count.js
代码语言:javascript复制 1 /*
2 该文件专门为Count组件生成action对象
3 */
4 import {INCREMENT,DECREMENT} from '../constant'
5
6 //同步action,就是指action的值为Object类型的一般对象
7 export const increment = data => ({type:INCREMENT,data})
8 export const decrement = data => ({type:DECREMENT,data})
9
10 //异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
11 export const incrementAsync = (data,time) => {
12 return (dispatch)=>{
13 setTimeout(()=>{
14 dispatch(increment(data))
15 },time)
16 }
17 }
9.redux/actions/person.js
代码语言:javascript复制1 import {ADD_PERSON} from '../constant'
2
3 //创建增加一个人的action动作对象
4 export const addPerson = personObj => ({type:ADD_PERSON,data:personObj})
10.containers/count.jsx
代码语言:javascript复制 1 import React, { Component } from 'react'
2 //引入action
3 import {
4 increment,
5 decrement,
6 incrementAsync
7 } from '../../redux/actions/count'
8 //引入connect用于连接UI组件与redux
9 import {connect} from 'react-redux'
10
11 //定义UI组件
12 class Count extends Component {
13
14 state = {carName:'奔驰c63'}
15
16 //加法
17 increment = ()=>{
18 const {value} = this.selectNumber
19 this.props.increment(value*1)
20 }
21 //减法
22 decrement = ()=>{
23 const {value} = this.selectNumber
24 this.props.decrement(value*1)
25 }
26 //奇数再加
27 incrementIfOdd = ()=>{
28 const {value} = this.selectNumber
29 if(this.props.count % 2 !== 0){
30 this.props.increment(value*1)
31 }
32 }
33 //异步加
34 incrementAsync = ()=>{
35 const {value} = this.selectNumber
36 this.props.incrementAsync(value*1,500)
37 }
38
39 render() {
40 //console.log('UI组件接收到的props是',this.props);
41 return (
42 <div>
43 <h2>我是Count组件,下方组件总人数为:{this.props.renshu}</h2>
44 <h4>当前求和为:{this.props.count}</h4>
45 <select ref={c => this.selectNumber = c}>
46 <option value="1">1</option>
47 <option value="2">2</option>
48 <option value="3">3</option>
49 </select>
50 <button onClick={this.increment}> </button>
51 <button onClick={this.decrement}>-</button>
52 <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
53 <button onClick={this.incrementAsync}>异步加</button>
54 </div>
55 )
56 }
57 }
58
59 //使用connect()()创建并暴露一个Count的容器组件
60 export default connect(
61 state => ({
62 count:state.count,
63 personCount:state.persons.length
64 }),
65 {increment,decrement,incrementAsync}
66 )(Count)
11.containers/persion.jsx
代码语言:javascript复制 1 import React, { Component } from 'react'
2 import {nanoid} from 'nanoid'
3 import {connect} from 'react-redux'
4 import {addPerson} from '../../redux/actions/person'
5
6 class Person extends Component {
7
8 addPerson = ()=>{
9 const name = this.nameNode.value
10 const age = this.ageNode.value*1
11 const personObj = {id:nanoid(),name,age}
12 this.props.addPerson(personObj)
13 this.nameNode.value = ''
14 this.ageNode.value = ''
15 }
16
17 render() {
18 return (
19 <div>
20 <h2>我是Person组件,上方组件求和为{this.props.count}</h2>
21 <input ref={c=>this.nameNode = c} type="text" placeholder="输入名字"/>
22 <input ref={c=>this.ageNode = c} type="text" placeholder="输入年龄"/>
23 <button onClick={this.addPerson}>添加</button>
24 <ul>
25 {
26 this.props.persons.map((p)=>{
27 return <li key={p.id}>{p.name}--{p.age}</li>
28 })
29 }
30 </ul>
31 </div>
32 )
33 }
34 }
35
36 export default connect(
37 state => ({
38 persons:state.persons,
39 count:state.count
40 }),//映射状态
41 {addPerson}//映射操作状态的方法
42 )(Person)