上节课我们已经完成了大致的一个流程,我们有了action,有了reducer,也把我们onClick事件的回调获得的值也封装成了一个对象,而且还通过nanoid来为每个对象生成了一个独有的id,那么接下来我们就把整个流程给实现吧。

回顾

上节课没有什么新的知识点,就一个默认参数的传递,我们就不多做赘述了,我们开始这节课的内容。

组件展示实现

我们现在整套流程已经架起来了,但是我们还没有实现,那么我们现在Person组件中来展示一下我们的效果,看看自身能不能拿到redux中的state

但是我现在要说一个问题,我们现在虽然有了actionreducer,但是实际上来说,我们这个reducer根本没有执行,我们来验证一下,在两个组件的reducer中分别打印组件名来看一下效果:

image-20220120095824112

大家看,控制台中只输出了sum,是不是代表着Sum组件的reducer被成功执行了?但是没有输入person,那么这是怎么回事儿呢?我们的reducer是不是由store来控制调度的?那么我们来到store里面来看一眼:

import { createStore,applyMiddleware } from 'redux';
import sumReducer from './reducers/sum';
import thunk from 'redux-thunk';

export default createStore(sumReducer,applyMiddleware(thunk));

大家有没有发现问题所在?第一我们没有导入personreducer,其次我们在最后一行创建store的时候,是不是把sumReducer传进去了?但是我们传personreducer了吗?是不是没有?所以说personreducer并没有被执行,那么我们怎么来改一下呢?

import { createStore, applyMiddleware, combineReducers } from 'redux';
import sumReducer from './reducers/sum';
import personReducer from './reducers/person';
import thunk from 'redux-thunk';

const allReducers = combineReducers({
  sum: sumReducer,
  person: personReducer
})

export default createStore(allReducers, applyMiddleware(thunk));

我们来看一下代码,我们导入了personReducer,那么我们怎么传到createStore函数里呢?我们之前可没有说createStore可以多个 reducer一直连续往里传,所以说我们要借助一个APIcombineReducers,这个API接收一个对象。

接下来我要讲一个很重要的点:combineReducers API接收到的对象就redux最终的状态的对象。

什么意思呢?我们之前还没有写Person组件的时候我们redux组件里面的state存的是什么?是不是就是一个数字?Sum组件要用的时候直接调用getState方法然后直接就获取到了这个数字。那么现在我们有了一个Person组件。这个组件也要往redux里面存数据,存了一个数组,那么这个state是不是就乱了啊?我们取数据如果getState的话,我们获取到的数据是什么呢?不知道是什么啊,所以说大家觉得redux中的state如果是一个对象的话,我们在存取数据的时候是不是就很方便了?

combineReducers API所接收到的这个对象,就是redux中的state对象。那么我们以后getState方法获取到的数据是不是就是一个对象,而不再是一个数字或者数组了。

那么我们来让Person组件上先来展示一下我们的输入信息:

export default class Person extends Component {
  componentDidMount() {
    store.subscribe(()=>this.setState({}))
  }
  render() {
    return (
      <div>
        <input ref={c => this.name = c} type="text" placeholder="input name" />
        <input ref={c => this.age = c} type="text" placeholder="input age" />
        <button onClick={this.addPerson}>submit</button>
        <div>
          {
            store.getState().person.map(p=><li id={p.id}>name: {p.name}, aeg: {p.age}</li>)
          }
        </div>
        <h2>当前求和为:{store.getState().sum}</h2>
      </div>
    )
  }
  addPerson = () => {
    const name = this.name.value;
    const age = this.age.value;
    const person = { id: nanoid(), name, age }
    store.dispatch(createAddPersonAction(person));
  }
}

我们来看一下代码,我们目前还没有写容器组件,所以说是直接操作的redux,那么我们是不是要用storedispatch?然后我们在展示的时候要从getState获取到的对象中取到person属性。那么我们把Sum组件的数据也拿过来吧。而且我们是不是直接操作的redux?那么我们是不是要手动监测reduxstate更新?现在我们再看一下页面:

image-20220120113624737

这一下是不是跑通了?那么接下来我们来把他改回UI组件,然后来创建容器组件吧。

class Person extends Component {
  render() {
    return (
      <div>
        <input ref={c => this.name = c} type="text" placeholder="input name" />
        <input ref={c => this.age = c} type="text" placeholder="input age" />
        <button onClick={this.addPerson}>submit</button>
        <h2>当前求和为:{this.props.sum}</h2>
      </div>
    )
  }
  addPerson = () => {
    const name = this.name.value;
    const age = this.age.value;
    const person = { id: nanoid(), name, age }
    this.props.add(person);
  }
}

export default connect(
  state => ({sum: state.sum}),
  { add: createAddPersonAction }
)(Person)

我们来看一下代码,我们取消对UI组件的暴露,对外默认暴露容器组件,我们说了connect要在第一次调用的时候传入另个参数:

  • 状态数据
  • 操作状态的方法

那么我们是不是要在Person组件中展示Sum组件的数据,使用我们就传入sum,顺便我们也改一下Sum组件中的展示吧:

class Sum extends Component {
  render() {
    return (
      <div>
        <select ref={c => this.selectNum = c}>
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>
        <button onClick={this.add}>+</button>
        <button onClick={this.dec}>-</button>
        <button onClick={this.odd}>odd</button>
        <button onClick={this.async}>async</button>
        <ul>
          {
            this.props.person.map(p=><li id={p.id}>name: {p.name}, age: {p.age}</li>)
          }
        </ul>
      </div>
    )
  }
  add = () => {
    const { value } = this.selectNum;
    this.props.increment(value * 1)
  }
  dec = () => {
    const { value } = this.selectNum;
    this.props.decrement(value * 1)
  }
  odd = () => {
    const { value } = this.selectNum;
    if (this.props.sum % 2 !== 0) this.props.increment(value * 1)
  }
  async = () => {
    const { value } = this.selectNum;
    this.props.asyncIncrement(value * 1, 500);
  }
}

export default connect(
  state => state,
  {
    increment: createIncrementAction,
    decrement: createDecrementAction,
    asyncIncrement: createAsyncIncrementAction
  }
)(Sum);

代码我就不多赘述了,我们单讲一下,我们的取数,为什么我们直接把satte里面这两个数据都拿了啊?因为我们有一个要判断奇数的操作。那么我们整体看一下效果吧:

iShot2022-01-20 11.55.33

这一下,我们的所有功能更久都实现了。现在我们的共享数据就已经完成了

总结

  • combineReducers函数整合reducer
  • combineReducers中接收一个参数是对象
  • combineReducers接收到的对象就是redux中的状态对象

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/finish_share_data/