Home > OS >  How to re-render content when my array of ingredients changes?
How to re-render content when my array of ingredients changes?

Time:12-25

I am trying to make a screen where users can edit recipes and one component is allowing users to edit the ingredients needed for the recipe.

Here, I have the text input component which is a custom component and a trash icon that allows users to delete that ingredient.

<View style={styles.listLabelContainer}>
            <BoldedText style={styles.labelText}>Ingredients</BoldedText>
            <TouchableOpacity
              activeOpacity={0.5}
              onPress={() => {
                addListItemHandler(ingredients);
              }}
            >
              <Ionicons
                name={Platform.OS === "android" ? "md-add" : "ios-add"}
                size={23}
                color={Colours.primary}
              />
            </TouchableOpacity>
          </View>
          <View>
            {ingredients.map((ingredient, index) => (
              <ListItem key={index}>
                <View style={styles.ingredientInputContainer}>
                  <View style={styles.ingredientInput}>
                    <Input
                      autoCorrect
                      keyboardType="default"
                      returnKeyType="done"
                      required
                      identifier="recipeIngredient"
                      initialValue={ingredient}
                      onInputChange={() => {}}
                    />
                  </View>
                  <TouchableOpacity
                    style={styles.deleteButton}
                    activeOpacity={0.5}
                    onPress={() => {
                      deleteListItemHandler(ingredients, index);
                    }}
                  >
                    <Ionicons
                      name={
                        Platform.OS === "android" ? "md-trash" : "ios-trash"
                      }
                      size={23}
                      color={Colours.primary}
                    />
                  </TouchableOpacity>
                </View>
              </ListItem>
            ))}
          </View>
        </View>

The functions to delete and add an ingredient are as follows:

const [ingredients, setIngredients] = useState(
    currentRecipe ? [...currentRecipe.ingredients] : []
  );

  const addListItemHandler = (arr) => {
    // add one empty string to end of array STEP
    setIngredients(arr.concat(""));
  };

  const deleteListItemHandler = (arr, index) => {
    // remove desired index ingredient STEP

    arr.splice(index, 1);
    setIngredients([...arr]);
  };

However, in the case where I have 5 ingredients and I choose to delete the 3rd ingredient, of array index 2, the array is updated accordingly. However, what is rendered is incorrect as the ingredient removed is the last ingredient and the ingredient to be removed is still present. My guess is that the value of the text input cannot be updated dynamically. However, is there a way to make this part of the code re-render whenever my ingredients array change so that the ingredients array is always the most updated one? This would allow for the correct rendering of ingredients.

Edit: I realise the issue is because the initialValue prop of the custom Input component is not updating whenever the array changes. Hence, what is displayed on the screen remains the same which causes the above error.

Thank you for the help.

CodePudding user response:

What I can see is that you are mutating the state and it looks like your state is not synced with the UI.

try something like this

const deleteListItemHandler = (arr, index) => {
    // remove desired index ingredient STEP
    const state = [...ingredients]
    state.splice(index, 1);
    setIngredients([...state]);
  };

or

const deleteListItemHandler = (arr, index) => {
    // remove desired index ingredient STEP

    setIngredients( oldState => [...oldState.splice(index, 1)]);
  };

CodePudding user response:

You don't need to pass the array again

const deleteListItemHandler = (index) => {
    ingredients.splice(index, 1);
    setIngredients([...ingredients]);
  };
  • Related