知道react-redux,但还不会多组件交互?

149 阅读3分钟

react-redux

前言

《每天学点React ~ react-redux》中,学习了react-redux的基本使用,但仅演示了一种组件而已,而在日常工作中,我们所需的组件肯定不止一个,会涉及相当多的组件,利用react-redux进行交互,那么本篇就来演示下多组件的场景下,如何利用react-redux进行交互吧。

前置准备

在上一个案例的基础上,我们新增多一个Person组件,将其添加在Count组件的下方,其内容是:

  • 一个名字输入框
  • 一个年龄输入框
  • 一个添加按钮
  • 一个列表展示已添加的信息

如下图所示 image.png

参考代码

import React, { Component } from 'react'

export default class Person extends Component {

    addPerson = () => {
        const nameNode = this.nameNode.value
        const ageNode = this.ageNode.value
        console.log(nameNode, ageNode)
    }
    render() {
        return (
            <div>
                <h2>PerSon组件</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>
                    <li>姓名1--年龄1</li>
                    <li>姓名2--年龄2</li>
                    <li>姓名3--年龄3</li>
                </ul>
            </div>
        )
    }
}

开始编码

  1. 定义常量
export const ADD_PERSON = 'add_person'
  1. 定义action
import { ADD_PERSON } from "../constant"

// 创建添加Person对象的Action
export const createAddPersonAction = data => ({ type: ADD_PERSON, data })
  1. 定义reducer
import { ADD_PERSON } from "../constant"

const initState = [{ name: '姓名', age: '年龄' }]

export default function personReducer(preState = initState, action) {
    const { type, data } = action
    switch (type) {
        case ADD_PERSON:
            return [data, ...preState]
        default:
            return preState
    }
} 
  1. App组件引入Person组件
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>
        )
    }
}

到了这里,是不是有小伙伴觉得就已经完成了呢?就跟Count组件一样可以运行了。

别急,我们在personReducer打印下看看有没有被初始化先。

export default function personReducer(preState = initState, action) {
    console.log('personReducer')
    const { type, data } = action
    switch (type) {
        case ADD_PERSON:
            return [...preState, data]
        default:
            return preState
    }
}

image.png

可以看到只有countReducer初始化了,personReducer没生效。仔细想一想,是不是还漏了什么没有定义呢?

store.js中,我们之前引入过countReducer的,但是新添加的组件并没有引入

image.png

所以redux并没有帮我们管理起来,我们还需要在该文件中引入personReducer交由其进行管理才行。这里需要注意的是,当有多个reducer需要交给redux管理的时候,我们需要引入combineReducers函数,由它来帮我们保存所有状态。

// 引入 createStore,用于创建store对象
import { legacy_createStore as createStore, applyMiddleware, combineReducers} from 'redux'

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

// 引入 thunk 中间件
import thunk from 'redux-thunk'

// 暴露store,combineReducers传入的对象就是redux帮我们保存的那个总状态对象
export default createStore(combineReducers({
    counts: countReducer,
    persons: personReducer
}), applyMiddleware(thunk))

既然reducer都交给combineReducers管理了,那么我们前面的使用connect创建组件的方式自然也需要做一定的改变了,需要获取到state中,我们刚刚定义的键对象才行。

// count
export default connect(
    state => ({ count: state.counts }),
    {
        increment: createIncrementAction,
        decrement: createDecrementAction,
        asyncIncrement: createIncrementAsyncAction,
    }
)(Count)

// person
export default connect(
    state => ({ person: state.persons }),
    // state => ({ person: state }),
    { addPerson: createAddPersonAction }
)(Person)

image.png

两个组件都正常初始化成功了。再来测试一下功能是否都能正常使用。

image.png

组件互通

到了这里,两个组件各自都能正常使用了,但是我们需要做的是组件之间也可以进行交互,那么应该如何做呢?

小伙伴们想一下,既然我们已经把reducer交由redux帮我们管理了,我们在使用connect定义的时候也是从props中拿到的状态,既然能拿到自己的,为什么不能拿到别的组件的呢?说做就做,尝试一下看看,在state中同时获取另一个组件状态

export default connect(
    state => ({ person: state.persons, count: state.counts }),
    { addPerson: createAddPersonAction }
)(Person)

image.png

可以看到是能正常获取到别的组件的,这样我们就可以实现组件间的交互了。

本文正在参加「金石计划 . 瓜分6万现金大奖」