简体   繁体   中英

Add new key value to Redux Toolkit state

I'm trying to create an app that will allow users to build a recipe and make changes to it. I'm using React Toolkit and Redux to manage the state.

Example state:

const ingredients = [
  {
    ingredientName: 'Flour',
    ingredientMeasurement: 500,
    ingredientUnit:'g',
    ingredientMeasurementUpdate: 0,
  },
  {
    ingredientName: 'Water',
    ingredientMeasurement: 200,
    ingredientUnit:'g',
    ingredientMeasurementUpdate: 0,
  },
  {
    ingredientName: 'Apples',
    ingredientMeasurement: 350,
    ingredientUnit:'g',
    ingredientMeasurementUpdate: 0,
  },

I have this slice for my ingredients. The updateFields is to add a new measurement and assign it to that ingredient.

const initialState = {
  ingrediants: [],
};

export const ingredientsSlice = createSlice({
  name: "ingredientList",
  initialState,
  reducers: {
    addIngredients: (state, action) => {
      state.ingrediants = [...state.ingrediants, action.payload];
    },
    removeIngrediants: (state, action) => {
      state.ingrediants = state.ingrediants.filter(
        (i) => i.id !== action.payload.id
      );
    },
    updateFields: (state, action) => {
      state.ingrediants = { ...state.ingrediants, ...action.payload };
    },
  },
});

export const { addIngredients, removeIngrediants, updateFields } = ingredientsSlice.actions;

export default ingredientsSlice.reducer;

I have this page that displays the list of ingredients:

const alteration = () => {
  return (
    <main className="h-screen flex">
      <div className="relative h-full w-1/3 border-4">
        <div className="absolute inset-y-0 left-0 w-80">
          <h1>Hello </h1>
          <RecipeList />
        </div>
      </div>
      <div></div>
    </main>
  );
};

export default alteration;

Here is the component that I would like it to update the state and add a new measurement


export const RecipeList = memo(() => {
  const ingredientList = useSelector(
    (state) => state.ingredientList.ingrediants
  );

  const dispatch = useDispatch();

  const [
    ingredientMeasurementUpdate,
    setIngrediantMeasurementUpdate,
  ] = useState();

  const onFormSubmit = useCallback(
    (e) => {
      e.preventDefault();

      dispatch(
        updateFields({
          ingredientMeasurementUpdate,
        })
      );

      setIngrediantMeasurementUpdate("");
    },
    [ingredientMeasurementUpdate, dispatch]
  );

  return (
    <div>
      <div>
        {ingredientList.map((ingredient) => (
          <div
            className="border-gray-800 border h-52 w-full"
            key={ingredient.id}
          >
            {` ${ingredient.ingredientMeasurement}${ingredient.ingredientUnit}  ${ingredient.ingredientName}`}{" "}
            <form onSubmit={onFormSubmit}>
              <fieldset>
                <input
                  className="border-2"
                  type="text"
                  value={ingredientMeasurementUpdate}
                  id="ingrediantunit"
                  onChange={(e) =>
                    setIngrediantMeasurementUpdate(e.target.value)
                  }
                ></input>
              </fieldset>

              <fieldset>
                <button type="submit">add</button>
              </fieldset>
            </form>
          </div>
        ))}
      </div>
    </div>
  );
});

I have another form that allows the user to add ingredients to their recipe


export const IngrediantsForm = memo(() => {
  const dispatch = useDispatch();

  const [ingredientName, setIngrediantName] = useState("");
  const [ingredientMeasurement, setIngrediantMeasurement] = useState();

  const [ingredientUnit, setIngrediantUnit] = useState("");

  const onFormSubmit = useCallback(
    (e) => {
      e.preventDefault();

      dispatch(
        addIngredients({
          ingredientName,
          ingredientMeasurement,
          ingredientUnit,
          id: uuidV4(),
        })
      );

      setIngrediantName("");
      setIngrediantMeasurement("");
      setIngrediantUnit("");
    },
    [ingredientName, ingredientMeasurement, ingredientUnit, dispatch]
  );

  return (
    <form onSubmit={onFormSubmit}>
      <fieldset>
        <input
          className="border-2"
          type="text"
          value={ingredientName}
          id="ingrediantname"
          onChange={(e) => setIngrediantName(e.target.value)}
        ></input>
      </fieldset>

      <fieldset>
        <input
          className="border-2"
          type="number"
          value={ingredientMeasurement}
          id="ingrediantmeasurement"
          onChange={(e) => setIngrediantMeasurement(e.target.value)}
        ></input>
      </fieldset>

      <fieldset>
        <input
          className="border-2"
          type="text"
          value={ingredientUnit}
          id="ingrediantunit"
          onChange={(e) => setIngrediantUnit(e.target.value)}
        ></input>
      </fieldset>

      <fieldset>
        <button className="border-2" type="submit">
          add
        </button>
      </fieldset>
    </form>
  );
});

I'm not entirely sure how to access the state (which is the list of ingredients) and then add another key/value to the object so that I have one key called ingredientMeasurement and another called ingredientMeasurementUpdate. The problem I believe is that it doesn't update the ingredientMeasurementUpdate on the right ingredient possibly because it doesn't know which one I need to update.

What I seem to get on Redux DevTools is this:

ingredientList: {
    ingrediants: {
      '0': {
        ingredientName: 'Apples',
        ingredientMeasurement: '100',
        ingredientUnit: 'g',
        ingredientMeasurementUpdate: 0,
        id: '455ed39b-57b9-4351-98a7-5845cae676b5'
      },
      '1': {
        ingredientName: 'Flour',
        ingredientMeasurement: '650',
        ingredientUnit: 'g',
        ingredientMeasurementUpdate: 0,
        id: 'e96349a1-e8ea-4cc6-aa68-6fbfc42ff87b'
      },
      ingredientMeasurementUpdate: '250'
    }
  }

in addIngredients use state.ingrediants.push(payload)

The problem is in your updateFields action you have to pass the particular ingrediant id in the payload to update the particular ingrediant in the array.

Change the whole code with the following code:

updateFields: (state, action) => {
  let index=state.ingrediants.findIndex((i)=>i.id===action.payload.id);
  if(index!=-1) {
      state.ingrediants[index]={...action.payload}
  }
},

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM