【问题标题】:redux reducer returns empty array when filtering stateredux reducer 过滤状态时返回空数组
【发布时间】:2017-03-26 01:13:33
【问题描述】:

对于我正在编写的 react 组件,我使用 redux 来管理组件的状态。我之前并没有真正使用过 redux,所以我在使用我编写的一个 reducer 时遇到了一些问题。我的 react 组件中的一种方法发出一个 http 请求,然后通过一个简单的操作函数将数据分派到 reducer。但是,我为这个减速器编写了另一个动作来从状态中删除条目,但是每当我使用这个动作时,减速器都会返回一个空数组。任何帮助表示赞赏。

减速器

export function Weeklystate(state=[], action){
    switch(action.type){
        case 'ADD_PROVIDER':
            return [...state, action.arr];

        case 'REMOVE_PROVIDER':
            const newstate = [...state];

            return newstate.filter((provider) => provider[0].full_name.toLowerCase().indexOf(action.str) === -1);

        default:
           return state;
    }
}

actions.js

export function addProvider(arr){
    return {
        type: 'ADD_PROVIDER',
        arr
    };
}

export function removeProvider(str){
    return {
        type: 'REMOVE_PROVIDER',
        str
    };
}

组件方法

getData(){
    const { url, queries } = this.state;
    let data_arr = [];

    const que = queries.map(function(query){
        let postquery = {
            full_name: query.name,
            date_start: query.startdate,
            date_end: query.enddate
         };

         return axios.post(url, postquery);
    });

    axios.all(que).then((responses) => {
        responses.forEach((response) => {
          this.props.addProvider(response.data);
        });
    });
}

componentWillMount(){
    this.getData();
    this.props.removeProvider('Example Name here');
    const { rawdata } = this.props;

    return console.log(this.props);
}

MaptoProps 函数

function mapStateToPropsBETA(state){
    return {
        rawdata: state.rawdata,
        parseddata: state.parseddata
    };
}

function mapDispatchtoProps(dispatch){
    return bindActionCreators({
        addProvider: addProvider,
        removeProvider: removeProvider

    }, dispatch);
}

export default connect(mapStateToPropsBETA, mapDispatchtoProps)(Weekly_Beta);

stores.js

const WeeklyStore = createStore(reducer);

WeeklyStore.subscribe(() => {
    console.log(WeeklyStore.getState());
});

export default WeeklyStore;

样本数据

[
 [
  {
      first_name: "First Name Here...", 
      last_name: "Last Name Here...",
      full_name: "Full Name Here",
      date: "2016-01-17",
      charges: {
          cosmetic: 25000.00,
          medical: 25000.00,
          total: 50000.00
      },
      payments: 75000.00,
      appointments: 99,
      pk: 5
  }, 
  {
      first_name: "First Name Here...", 
      last_name: "Last Name Here...",
      full_name: "Full Name Here",
      date: "2016-01-24",
      charges: {
          cosmetic: 25000.00,
          medical: 25000.00,
          total: 50000.00
      },
      payments: 75000.00,
      appointments: 99,
      pk: 5
   }, 
 ],
[
 {
     first_name: "First Name Here...", 
     last_name: "Last Name Here...",
     full_name: "Full Name Here",
     date: "2016-01-17",
     charges: {
         cosmetic: 25000.00,
         medical: 25000.00,
         total: 50000.00
     },
     payments: 75000.00,
     appointments: 99,
     pk: 5
 }, 
 {
      first_name: "First Name Here...", 
      last_name: "Last Name Here...",
      full_name: "Full Name Here",
      date: "2016-01-24",
      charges: {
          cosmetic: 25000.00,
          medical: 25000.00,
          total: 50000.00
      },
      payments: 75000,
      appointments: 99,
     pk: 5
  },
 ]
];

更新

我做了一些测试,得到了一些奇怪的结果。我在 chrome 上的控制台内执行了相同的代码,我的一切都运行得很好。但是,reducer 仍然返回一个空数组。


更新 #2

经过进一步的故障排除后,我想我可能对导致状态写入不正确的原因有了更好的了解。我能够让扩展运算符正常工作,因此此时数据不变性不是什么大问题。

但是,在进行故障排除时,我碰巧注意到了两件事。当 redux 状态发生变化时,保存我的 redux 状态的组件 props 不会被更新。为了确认这一点,我使用 subscribe 方法在分派操作时为我提供状态。 rawdata 的字段填充了我在 redux 状态下要查找的数据,但是,数据没有被推送到等效的组件道具。

我注意到的第二件事是 REMOVE_PROVIDER 操作没有调度,因为 subscribe 方法没有在控制台中报告任何内容。我不确定为什么会发生这种情况,但我认为filter 可能是原因,因为每当我尝试调度操作时,redux 状态都保持不变。

在这一点上,我确信我遇到的问题更多是 react-redux 问题,而不是 reducer 本身的问题。我还冒昧地更新了我的代码 sn-ps 以反映我所看到的。

来自 react 组件的 props 日志

来自 redux 存储的日志条目

【问题讨论】:

  • 你不能改变状态。需要创建一个newState 然后返回它。
  • 那我该如何处理呢?我知道很多人建议使用扩展运算符来帮助实现这一目标,但由于某种原因我无法让它为我工作。请注意,我对 redux 也还是很陌生。
  • 设置变量let newState = state;,然后将过滤器应用于newState,并返回newState。你在正确的轨道上。
  • 或者只是 return state.filter(...) 就足以不变异
  • @Ryan27。如果您回顾一下减速器的功能,我会按照您的建议进行更改。虽然我在运行 'REMOVE_PROVIDER' 操作时仍然返回一个空数组。

标签: javascript arrays json reactjs redux


【解决方案1】:

如果您的示例准确,则只需将 REMOVE_PROVIDER 大小写更改为

case 'REMOVE_PROVIDER':
            return newstate.filter((provider)=> provider[0].full_name.indexOf(action.data) === -1);

正如您在问题中所写,过滤器将返回所有名称为“示例名称”的提供者。他们都不是。您希望相反,即返回名称与输入名称不匹配的所有提供者。

【讨论】:

  • 我在这个例子中做了同样的事情,但它仍然返回空
【解决方案2】:
  1. 首先,您的ADD_PROVIDER 直接改变state,添加newstate = state 不会复制状态数组,因为它只会创建对状态的引用。

  2. 对于您的ADD_PROVIDERaction.data 是什么?根据您的操作,它本身已经是一个数组,但是您用另一个数组表示法包装它,您的状态变成了数组数组的数组。 -____-?.

  3. 正如另一个答案所建议的那样,您的 REMOVE_PROVIDER 逻辑是错误的,您保留了全名具有 action.data 的所有 prodivers。

要修复,你的减速器应该是:

export function Weeklystate(state=[], action){
    switch(action.type){
    case 'ADD_PROVIDER':
        return [...state, action.data]; // this returns a new array

    case 'REMOVE_PROVIDER':
        // this will keep provider whose full_name does not have action.data
        return state.filter((provider)=>provider[0].full_name.indexOf(action.data.full_name) === -1);

    default:
        return state;
    }
}

正如我的第二点建议的那样,我不确定您希望自己的状态如何,因此请相应地进行修复。使用此代码,我假设 ADD_PROVIDER action.data 是一个包含 1 个元素的数组。

【讨论】:

  • 除了在ADD_PROVIDER 的解决方案中,您使用扩展运算符来克隆状态。我已经尝试过这样做,它不起作用。
猜你喜欢
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
  • 2017-02-07
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多