【问题标题】:How to use a reducer for multiple actions in Redux?如何在 Redux 中使用 reducer 执行多个操作?
【发布时间】:2019-07-01 21:08:09
【问题描述】:

我是使用 Redux 的新手,我正在尝试将 React 与 Redux 集成。我想要的是把我所有的动作都放在一个减速器中。实际上我的减速器是这样的:

import {GET_ALL_CONNECTIONS, DELETE_CONNECTION, POST_CONNECTION} from '../actions';

const initialState = {

}

export default (state = initialState, { type, payload }) => {
    switch (type) {

    case GET_ALL_CONNECTIONS:
        return payload

    case POST_CONNECTION:
        return {...state, ...payload}

    case DELETE_CONNECTION:
        return {...state, ...payload}

    default:
        return state
    }
}

问题是当我调用 GET_ALL_CONNECTIONS 类型对应的操作时:

export const getAllConnections = () => {
    return async (dispatch) =>{
        const response = await Conexiones.get('/db/myConnections');
        dispatch({type: GET_ALL_CONNECTIONS, payload: response.data});
    }
}

当我在 React 组件中调用此函数时,应该从 API 获取多个连接,并将 API 调用结果的对象数组保存在状态中。 问题是当我想将连接数组保存在状态中时,以便稍后映射该状态并生成options,其中每个连接都位于select 元素内。当我渲染组件时,它会抛出下一个错误:

TypeError: this.props.conexiones.map is not a function

我合并所有 reducer 的文件如下所示:

import {combineReducers} from 'redux';
import {reducer as formReducer } from 'redux-form';

    import postUser from './postUser';
    import postConnection from './postConnection';
    import getAllConnections from './getAllConnections';
    import ConnectionsReducer from './ConnectionsReducer';

    export default combineReducers({
        newUser: postUser,
        form: formReducer,
        conexiones: ConnectionsReducer
    });

我调用的组件如下所示:

import React, { Component } from 'react';
import { Grid, Container, Select, Button, withStyles, FormControl, InputLabel, MenuItem } from '@material-ui/core';
import {connect} from 'react-redux';
import {reduxForm, Field} from 'redux-form';


import {deleteConnection, getAllConnections} from '../actions';

const styles = theme => ({
    root: {
        display: 'flex',
        flexWrap: 'wrap',
    },
    formControl: {
        margin: theme.spacing(1),
        minWidth: 120,
    },
    selectEmpty: {
        marginTop: theme.spacing(2),
    },
});

class BorrarConexion extends Component {

    componentDidMount() {
        this.props.getAllConnections();
    }

    handleSubmit = ({conexionId}) => {
        this.props.deleteConnection(conexionId);
    }

    renderConexiones = () => {
        return this.props.conexiones.map(conexion =>{
            return (<MenuItem key={conexion.id} value={conexion.id}>{conexion.connectionUrl}</MenuItem>);
        });
    }

    renderSelectField = ({input,label,meta: { touched, error },children,...custom}) =>{
        return (
        <FormControl>
            <InputLabel>Seleccione la URL que desea eliminar</InputLabel>
            <Select {...input} {...custom}>
                {this.renderConexiones()}
            </Select>
        </FormControl>
        )
    }

    render() { 
        return (
            <Container>
                <Grid container direction="column">
                    <Field name="conexionId" component={this.renderSelectField} label="Favorite Color"/>
                    <Button onClick={this.props.handleSubmit(this.handleSubmit)}>Eliminar</Button>
                </Grid>
            </Container>
        );
    }
}

const mapStateToProps = (state) => {
    return {conexiones: state.conexiones}  
}

const BorraConexionEstilizado = withStyles(styles)(BorrarConexion);
const formWrapped = reduxForm({form: 'delete_connection'})(BorraConexionEstilizado);

export default connect(mapStateToProps, {getAllConnections, deleteConnection})(formWrapped);

当我使用名为 getAllConnections 的单独减速器执行此操作并将 conexiones: ConnectionsReducers 替换为 conexiones: getAllConnections 时,它可以工作。 getAllConnections 减速器如下所示:

export default (state = [], { type, payload }) => {
    switch (type) {

    case 'GET_ALL_CONNECTIONS':
        return payload

    default:
        return state
    }
}

我想知道如何使用一个reducer 接收我的所有操作而不是每个操作的单个reducer 来完成这项工作。

【问题讨论】:

    标签: javascript reactjs redux


    【解决方案1】:

    此问题与您可能从减速器返回不同结构的事实有关。看起来 reducer 旨在将对象作为状态处理,但在这种情况下,您返回一个数组。对象没有地图功能。您需要确定此 reducer 的状态结构并坚持下去,您不能从数组更改为对象然后再返回,这是 redux 不适合的不确定行为。

    我不知道你们 API 的实现细节,但这是需要更新的主要领域

      const initialState = []
    
      export default (state = initialState, { type, payload }) => {
          switch (type) {
    
          case GET_ALL_CONNECTIONS:
              return payload //hoping that your api gave an array here
    
          case POST_CONNECTION:
              //return {...state, ...payload} //this is clearly returning an object
              return [...state, payload] //now it returns an array with a new item
    
          case DELETE_CONNECTION:
              //return {...state, ...payload} //this is clearly returning an object
              return state.filter(item => item.id !== payload.id) //now it returns a filtered array
    
          default:
              return state
          }
      }
    

    以下代码应将状态作为数组接收,并将更新后的状态作为数组返回。

    【讨论】:

    • 但是减速器正在返回一个数组。为什么 getAllConnections reducer 可以工作,而 ConnectionsReducer 却不行?我不明白
    • 已更新评论,请提出任何后续问题。在不知道 API 详细信息的情况下,我无法 100% 准确地回答您的问题
    • 我已经更新了代码,但仍然显示地图错误。我注意到的是,如果我在 getAllConnections 操作中放置一个控制台日志,打印 response.data,它将连接打印为一个数组,如果我在 BorrarConexiones componentDidMount() 方法上控制台日志 props.conexiones,在它调用函数 getAllConnections 之后,它打印一个没有元素的数组,是在我打开选择器后 props.conexiones 打印带有连接的数组。你认为这就是错误发生的原因吗?所有这些都使用conexiones:getAllConnections 作为减速器。
    • 您应该诚实地在 renderConexiones 中记录该值并查看该值是什么,获取后立即记录将始终给出一个空数组,因为您还没有等待承诺解决
    • 我在那里记录它并返回一个对象数组
    【解决方案2】:

    你必须设置初始状态...现在,你的状态是一个空对象

    【讨论】:

    • 我用什么来初始化它?和空数组?还是调用函数来获取所有连接?
    • 一个空数组。您应该以数据类型一致的方式设计您的 reducer。
    【解决方案3】:

    我通过用Object.values() 包围mapStateToProps 方法中的conexion:state.conexion 解决了这个问题,如下所示:

    conexion: Object.values(state.conexion)
    

    【讨论】:

    • 如果这确实是解决方案,那么您的 Conexiones.get(&amp;#39;/db/myConnections&amp;#39;) 函数有问题,它可能返回一个对象而不是预期的数组。您的解决方案更像是一种将对象的值转换为数组的技巧
    猜你喜欢
    • 2016-12-15
    • 1970-01-01
    • 2016-05-30
    • 2020-09-12
    • 1970-01-01
    • 2017-10-03
    • 1970-01-01
    • 2018-01-12
    • 2019-01-11
    相关资源
    最近更新 更多