React learning 27 (react-redux multi-component sharing data)

project structure

 Preparation

1) Define a person component and share data with the count component through redux

2) Write for the person component: reducer, action and contant constants

3) Key points: The reducer of Person and the reducer of Count should be merged with combineReducers, the total state after the merger

is an object

4) The general reducer is handed over to the store. Finally, when taking out the state in the component, remember to take it in place

code display

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App.jsx'
import store from './redux/store'//为provider服务
import {Provider} from 'react-redux'

ReactDOM.render(
<Provider store= {store}>
  <App/>
</Provider>,
document.getElementById('root')
)

// 检测redeux中状态的改变,若redux的状态发生了改变,那么重新渲染App组件
//使用react-redux创建容器组件后,react-redux可以自己实现检测state中状态的改变,所以可以删除
//以下代码
// store.subscribe(() => {
//   ReactDOM.render(<App/>,document.getElementById('root'))
// })

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>
    )
  }
}

redux-store.js

/*
  该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象,applyMiddleware用于支持
//异步action的中间件
//combineReducers用于合并多个reducer
import {createStore,applyMiddleware,combineReducers} from 'redux'

//引入为Count组件服务的reducer
import countReducer from './reducers/count'

//引入为Person组件服务的reducer
import personReducer from './reducers/person'

//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

//汇总所有的reducer变为一个总的reducers
const allReducer = combineReducers({
  he:countReducer,
  rens:personReducer
})

export default createStore(allReducer, applyMiddleware(thunk))

redux-content.js

/*
  该文件是用于定义action对象中的type类型的常量值
  目的只有一个:防止程序员在编码的同时单次写错
*/

export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

redux-actions-count.jsx

/*
  该文件专门为count组件生成action对象
*/
import { INCREMENT, DECREMENT } from "../constant"
//完整写法
// function createIncrementAction(data) {
//   return {type:'increment', data }
// }
//简写形式
//同步action,就是值action的返回值是Object类型的一般对象
export const createIncrementAction = data =>( {type:INCREMENT, data })

//完整写法
// function createDecrementAction(data) {
//   return {type:'decrement', data}
// }
export const createDecrementAction = data =>( {type: DECREMENT, data })

//异步action,就是值action的返回值是函数,异步action一般都会调用同步action
//异步action不是必须要用的
export const createIncrementAsyncAction = (data, time) =>{
  return (dispatch) => {
    setTimeout(() => {
      dispatch(createIncrementAction(data))
    },time)
  }
}

redux-actions-person.js

import {ADD_PERSON} from '../constant'

//创建增加一个人的action对象
export const creatAddPersonAction = personObj => ({type:ADD_PERSON, data:personObj})

redux-reducers-count.js

/*
  1.该文件用于创建一个为count组件服务的reducer,reducer的本质就是一个函数
  2.reducer函数会接到两个参数,分别是之前的state(状态)和action(动作对象)
*/
import { INCREMENT, DECREMENT } from "../constant";

const initState = 0
export default function countReducer(preState=initState, action) {
  console.log(preState, action);
  //从action对象中获取type, data
  const {type, data} = action
  //根据type类型决定如何加工
  switch (type) {
    case INCREMENT:// 如果是加
     return preState + data
    case DECREMENT:// 如果是减
      return preState - data
    default:
      return preState
  }
}

redux-reducers-person.js

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
  }
}

containers-count-index.jsx

//引入CountUI组件
// import CountUI from '../../compoents/Count'

import React, { Component } from 'react'

//引入connect用于连接UI组件和redux
import {connect} from 'react-redux'
//引入action
import {
  createIncrementAction,
  createDecrementAction,
  createIncrementAsyncAction
} from '../../redux/actions/count'

//定义UI组件
class Count extends Component {
  state = {carName:'奔驰c63'}//  把状态交给reducer之后组件也可以有自己独用的状态


  increment = () => {
    const {value} = this.selectNum
    this.props.jia(value*1)

  }
  decrement = () => {
    const {value} = this.selectNum
    this.props.jian(value*1)
  }
  incrementOdd = () => {
    const {value} = this.selectNum
    if(this.props.count % 2 !== 0) {
      this.props.jia(value*1)
    }
  }
  incrementWait = () => {
    const {value} = this.selectNum
    this.props.jiaAsync(value*1,400)
  }
  render() {
    console.log('UI组件接收到的props是:',this.props);
    return (
      <div>
        <h2>我是Count组件,下方组件总人数是{this.props.renshu}</h2>
        <h3>当前求和为:{this.props.count}</h3>
        <select ref={c => {this.selectNum = 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.incrementOdd}>当前求和为奇数再加</button>&nbsp;
        <button onClick= {this.incrementWait}>等一等再加</button>
      </div>
    )
  }
}

//使用connect()()创建并暴露一个Count容器组件
export default connect(
  state => ( {count:state.he,renshu:state.rens.length}), 
  //mapDispatchToProps的一般写法
  // dispatch => ({
  //   jia:number => dispatch(createIncrementAction(number)),
  //   jian:number => dispatch(createDecrementAction(number)),
  //   jiaAsync:(number,time) =>dispatch(createIncrementAsyncAction(number,time)) 
  // })

   //mapDispatchToProps的简写,dispatch由react-redux来完成,程序员工作中用这种方法
   {
    jia:createIncrementAction,
    jian:createDecrementAction,
    jiaAsync:createIncrementAsyncAction
   }
  )(Count)

containers-Person-index.jsx

import React, { Component } from 'react'
import {nanoid} from 'nanoid'
import {connect} from 'react-redux'
import {creatAddPersonAction} 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="请输入姓名"/>&nbsp;
        <input ref={c => this.ageNode = c} type="text" placeholder="请输入年龄"/>&nbsp;
        <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:creatAddPersonAction}//映射操作状态的方法
)(Person)

pure function

A. A special type of function: As long as it is the same input (actual parameter), it must get the same output (return)

B. Some of the following constraints must be followed

        Do not rewrite parameter data;

        Does not produce any side effects, such as: network requests, input and output devices;

        Impurity methods such as Date.now() or Math.random() cannot be called

C. The reducer function of redux must be a pure function

Guess you like

Origin blog.csdn.net/xiaojian044/article/details/128358670