React学习29(react-redux最终完整版)

说明

1)所有变量名字要规范,尽量触发对象的简写形式

2)reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer

项目结构

 

代码示例

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包裹App,目的是让App所有的后代容器组件都能够接收到store
<Provider store= {store}>
  <App/>
</Provider>,
document.getElementById('root')
)

App.jsx

import React, { Component } from 'react'
import Count from './containers/Count'//引入的是Count的容器组件
import Person from './containers/Person'//引入的是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} from 'redux'

//引入汇总之后的reducers
import reducer from './reducers'

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

//引入redux-devtools-extension
import {composeWithDevTools} from 'redux-devtools-extension'

export default createStore(reducer, composeWithDevTools(applyMiddleware(thunk)))

redux-constant.js

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

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

redux-reducers-index.js

/*
  该文件用于汇总会有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import {combineReducers} from 'redux'

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

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

//汇总所有的reducer变为一个总的reducers 
export default combineReducers({
  count,
  persons
})

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

redux-actions-count.js

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

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

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

redux-actions-person.js

import {ADD_PERSON} from '../constant'

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

container-count-index.jsx

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

import React, { Component } from 'react'

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

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


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

  }
  decrement = () => {
    const {value} = this.selectNum
    this.props.decrement(value*1)
  }
  incrementOdd = () => {
    const {value} = this.selectNum
    if(this.props.count % 2 !== 0) {
      this.props.increment(value*1)
    }
  }
  incrementWait = () => {
    const {value} = this.selectNum
    this.props.incrementAsync(value*1,400)
  }
  render() {
    console.log('UI组件接收到的props是:',this.props);
    return (
      <div>
        <h2>我是Count组件,下方组件总人数是:{this.props.personCount}</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.count,
    personCount:state.persons.length
  }), 
  //mapDispatchToProps的一般写法
  // dispatch => ({
  //   jia:number => dispatch(createIncrementAction(number)),
  //   jian:number => dispatch(createDecrementAction(number)),
  //   jiaAsync:(number,time) =>dispatch(createIncrementAsyncAction(number,time)) 
  // })

   //mapDispatchToProps的简写,dispatch由react-redux来完成,程序员工作中用这种方法
   {
    increment,
    decrement,
    incrementAsync
   }
  )(Count)

container-person-index.jsx

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
    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="请输入姓名"/>&nbsp;
        <input ref={c => this.ageNode = c} type="text" placeholder="请输入年龄"/>&nbsp;
        <button onClick= {this.addPerson}>添加</button>
        <ul>
         {
            this.props.persons.map((p) => {
              return <li key={p.id}>{p.name}--{p.age}</li>
            })
         }
        </ul>
      </div>
    )
  }
}

export default connect(
  state => ({
    persons:state.persons,
    count:state.count
  }),// 映射状态
  {addPerson}//映射操作状态的方法
)(Person)

猜你喜欢

转载自blog.csdn.net/xiaojian044/article/details/128360529