更改阵列中的数组的适当组件树

时间:2018-05-03 08:25:40

标签: javascript reactjs react-native redux react-redux

我正在试图理解我应该使用的组件结构。我觉得这是我绝对想要正确的事情,因为要了解ReactJS应用程序应该如何看待以及如何正确分离关注点,这一点非常重要。我知道这是一个固执己见的前线,但我目前的做法是不正确的,我正在寻找一些见解。

数据模型:这是一大堆食谱,每个食谱包含另一组成分。我希望允许用户勾选" (成分从阵列中除去)成分,因为他们购买/获得它们。

[
    ...
    {
        "title": "Recipe 1"
        "ingredients": [
            { "title": "Flour", "measurement": "300g" },
            { "title": "Sesame Seeds", "measurement": "1 Tblsp" }
        ]
    },
    ...
]

当前的Psuedo组件树:

// RecipeList is my "HOC" (higher-order component) and contains all the functions/data required for the rest of the tree, and simply passes them down as props. This is `connect()`ed to the store here.
<RecipeList>
    // Map on the highest level array to display a <Recipe> component for each
    <Recipe data={recipe[mappedIndex]}>
        // Map on each ingredient to create a list item for each
        <RecipeIngredient data={recipe[mappedIndex].ingredient[mappedIndex]>
            <IngredientCheckBox onChange={ //remove this ingredient from the array } />
        </RecipeIngredient>
    </Recipe>
</RecipeList>

上述所有情况都很好,数据显示的确切方式如何。

然而,这是主要问题,当涉及到onChange时,我调用了一个操作,COMPLETE_INGREDIENT基本上将其从ingredients数组中移除(我看到它在运作中,使用redux-logger next-state不包含它。)

不幸的是,我的组件不会重新渲染。它不再在阵列中,但仍显示在屏幕上。我理解这可能是以下原因之一:

  • connect()只比浅比较状态,因此它不会触发重新渲染,因为它是数组中的值,在数组中对象的属性内。
  • 我的connect()距离操作太远了,应该在更深的组件级别重新connect(),比如说<Recipe>组件,只将它附加到商店的一部分它关心的问题(甚至可能是<RecipeIngredient>)。
  • 我的reducer不是以不可变的方式修改状态。这是我花费最多的时间,但即使使用slice()和各种各样,我仍然无法重新渲染

编辑:我的行动减速机COMPLETE_INGREDIENT。我理解这可能是问题,因为它直接改变了国家。如此深刻改变国家的正确方法是什么?

case COMPLETE_INGREDIENT:
    // state is from a level above the recipe's, that contains a timestamp etc
    state.recipes[action.payload.recipeIndex].ingredients.splice(action.payload.ingredientIndex, 1)

    return Object.assign({
        ...state
    })

2 个答案:

答案 0 :(得分:1)

  

编辑:我的动作减速器COMPLETE_INGREDIENT。我明白这可能   是问题,因为它直接改变了国家。会是什么   如此深刻改变国家的正确方法?

是的,你正在用Object.assign改变状态。作为第一个参数,它应该有新的Object来复制值并返回:

return Object.assign({}, {
    ...state
})

根据你的代码,我创建了更新函数,我可能会创建:

case COMPLETE_INGREDIENT: {
  const { recipeIndex, ingregientIndex } = action.payload;
  const recipesListCopy = [...state.recipes];
  const recipeCopy = {
    ...recipesListCopy[recipeIndex],
    ingredients: recipesListCopy[recipeIndex].ingredients.filter(
      (e, index) => index !== ingredientIndex
    )
  };
  recipesListCopy[recipeIndex] = recipeCopy;
  return {
    ...state,
    recipes: recipesListCopy
  };
}

编辑:

基于您的评论 - “如果配料阵列现在为空,则从顶级配方数组中删除配方”

case COMPLETE_INGREDIENT: {
  const { recipeIndex, ingregientIndex } = action.payload;
  const recipesListCopy = [...state.recipes];
  const updatedIngredientsList = recipesListCopy[recipeIndex].ingredients.filter(
    (e, index) => index !== ingredientIndex
  );

  if(updatedIngredientsList.length > 0) { 
    // update ingredients
    const recipeCopy = {
      ...recipesListCopy[recipeIndex],
      ingredients: updatedIngredientsList
    };
    recipesListCopy[recipeIndex] = recipeCopy;
  } else { 
    // remove recipe because no igridients
    recipesListCopy.splice(recipeIndex, 1);
  }

  return {
    ...state,
    recipes: recipesListCopy
  };
}

答案 1 :(得分:1)

这里的问题在于改变现有的状态

case COMPLETE_INGREDIENT:
// state is from a level above the recipe's, that contains a timestamp etc
state.recipes[action.payload.recipeIndex].ingredients.splice(action.payload.ingredientIndex, 1)

return Object.assign({
    ...state
})

方法splice更改现有数组,但您需要创建新数组。这是示例

const obj = { a: { b: 5 } };
const copyObj = { ...obj };
copyObj.a.b = 1;
console.log(obj.a.b); // 1
console.log(copyObj.a.b); // 1

您已复制state个对象,但ingredients数组保持不变。所以你需要复制数组。

case COMPLETE_INGREDIENT:
return {
  ...state,
  recipes: state.recipes.map(
    (item, index) =>
      index === action.payload.recipeIndex
        ? { ...item, ingredients: item.ingredients.filter((item, index) => index !== action.payload.ingredientIndex) }
        : item
  ),
};