如何使用 redux、immer、react 从数组中删除元素

Ros*_*tyk 4 reactjs redux immer.js react-hooks

import produce from "immer";\n\nconst initialState = {\n  isLoading: true,\n  error: "",\n  burgers: [],\n};\n\nexport default function (state = initialState, action) {\n  switch (action.type) {\n    case "ADD_BURGER_BUCKET": {\n      return produce(state, (draftState) => {\n        if (Array.isArray(action.payload)) {\n          draftState.burgers.push(...action.payload);\n        } else {\n          draftState.burgers.push(action.payload);\n        }\n      });\n    }\n    case "REMOVE_BURGERS_BUCKET": {\n      return produce(state, (draftState) => {\n        draftState.burgers = []\n      });\n    }\n    **case "REMOVE_ONE_BURGER_BUCKET": {\n      return produce(state, (draftState) => {\n        console.log(action.payload, draftState.burgers) console.log => 3 Proxy\xc2\xa0{0: {\xe2\x80\xa6}}\n        draftState.burgers.filter(el => el.id !== action.payload)\n      })\n    }** HERE THIS ONE DOES NOT WORK!!!\n    default:\n      return state;\n  }\n}\n\n\nreturn ( <===== BURGER BUTTON\n                <Burger\n                  key={burger.id}\n                  text={burger.name}\n                  cost={burger.cost}\n                  onClick={() => {\n                    dispatch({\n                      type: "REMOVE_ONE_BURGER_BUCKET",\n                      payload: burger.id, <=== PASS ID TO REDUCER\n                    }); <==== THIS ONE DOESN'T REMOVE THE ELEMENT FROM AN ARRAY\n                    localStorage.setItem("burger", JSON.stringify(burger));\n                    localStorage.setItem(\n                      "burgersBucket",\n                      JSON.stringify(\n                        list.burgers.filter((el) => el.id !== burger.id)\n                      )\n                    );\n                    history.push("/redo");\n                  }}\n                />\n              );\n            }\n
Run Code Online (Sandbox Code Playgroud)\n

我想通过 id 从数组中删除元素,但我做不到,这就是我在控制台中得到的

\n

3 代理\xc2\xa0{0: {\xe2\x80\xa6}}

\n

我导入了 useselector 和 useDispatch 挂钩。

\n

完整代码

\n
    import React from "react";\n\nimport { Wrapper } from "../../styled/general";\nimport { Menu, MenuTitle, Burgers } from "../home/homestyled";\nimport Burger from "../../component/burger";\nimport { useDispatch, useSelector } from "react-redux";\nimport { useEffect } from "react";\nimport { useHistory } from "react-router-dom";\n\nexport default function Index() {\n  const list = useSelector((state) => state.burgerBucket);\n  const dispatch = useDispatch();\n  const history = useHistory();\n\n  useEffect(() => {\n    console.log(list.burgers);\n    if (list.burgers.length > 0) {\n      localStorage.setItem("burgersBucket", JSON.stringify(list.burgers));\n    } else {\n      let burgersBucket = JSON.parse(localStorage.getItem("burgersBucket"));\n      dispatch({ type: "ADD_BURGER_BUCKET", payload: burgersBucket });\n    }\n  }, []);\n\n  return (\n    <Wrapper>\n      <Menu>\n        <MenuTitle>My Bucket</MenuTitle>\n        <Burgers>\n          {[...list.burgers, { finish: true }, { addMore: true }].map(\n            (burger) => {\n              if (burger.addMore) {\n                return (\n                  <Burger\n                    key={-2}\n                    bg={"lightgreen"}\n                    text={"\xd0\x94\xd0\xbe\xd0\xb4\xd0\xb0\xd1\x82\xd0\xb8 \xd1\x89\xd0\xb5"}\n                    onClick={() => {\n                      history.push("/");\n                    }}\n                  />\n                );\n              }\n              if (burger.finish) {\n                return (\n                  <Burger\n                    key={-1}\n                    bg={"#ff5050"}\n                    text={"\xd0\x97\xd0\xb0\xd0\xb2\xd0\xb5\xd1\x80\xd1\x88\xd0\xb8\xd1\x82\xd0\xb8"}\n                    onClick={() => {\n                      dispatch({ type: "REMOVE_BURGERS_BUCKET" });\n                      history.push("/");\n                    }}\n                  />\n                );\n              }\n              return (\n                <Burger\n                  key={burger.id}\n                  text={burger.name}\n                  cost={burger.cost}\n                  onClick={() => {\n                    dispatch({\n                      type: "REMOVE_ONE_BURGER_BUCKET",\n                      payload: burger.id,\n                    });\n                    localStorage.setItem("burger", JSON.stringify(burger));\n                    localStorage.setItem(\n                      "burgersBucket",\n                      JSON.stringify(\n                        list.burgers.filter((el) => el.id !== burger.id)\n                      )\n                    );\n                    history.push("/redo");\n                  }}\n                />\n              );\n            }\n          )}\n        </Burgers>\n      </Menu>\n    </Wrapper>\n  );\n}\nenter code here\n
Run Code Online (Sandbox Code Playgroud)\n

完整的代码缩减器

\n
import produce from "immer";\n\nconst initialState = {\n  isLoading: true,\n  error: "",\n  burgers: [],\n};\n\nexport default function (state = initialState, action) {\n  switch (action.type) {\n    case "ADD_BURGER_BUCKET": {\n      return produce(state, (draftState) => {\n        if (Array.isArray(action.payload)) {\n          draftState.burgers.push(...action.payload);\n        } else {\n          draftState.burgers.push(action.payload);\n        }\n      });\n    }\n    case "REMOVE_BURGERS_BUCKET": {\n      return produce(state, (draftState) => {\n        draftState.burgers = []\n      });\n    }\n    case "REMOVE_ONE_BURGER_BUCKET": {\n      return produce(state, (draftState) => {\n        console.log(action.payload, draftState.burgers)\n        draftState.burgers.filter(el => el.id !== action.payload)\n      })\n    }\n    default:\n      return state;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

另外,也许这个很重要,这是用户单击汉堡按钮后我会重定向的代码(页面)

\n

完整代码

\n
import React, { useEffect, useState, useContext } from "react";\n\nimport { Wrapper } from "../../styled/general";\nimport { Menu, MenuTitle } from "../home/homestyled";\nimport {\n  BurgerIngridients,\n  IngridientWrapper,\n  BurgerDetails,\n  DetailsTitle,\n  IngridientsDetails,\n  Total,\n  DetailsButtonContinue,\n} from "./burgerredostyled";\nimport Ingridient from "../../component/Ingridient";\nimport IngridientdetailBlock from "../../component/IngridientsDetailBlock";\n\nimport { useHistory } from "react-router-dom";\nimport { useDispatch, useSelector } from "react-redux";\nimport { useBurger } from "../../hooks/useBurger";\n\nimport { sumOfToppings } from "../../helpers/sum";\n\nexport default function Index() {\n  const burger = useSelector((state) => state.burger);\n  const [toppings, error, isLoading] = useBurger(\n    "http://localhost:3000/toppings"\n  );\n  const dispatch = useDispatch();\n  const history = useHistory();\n\n  useEffect(() => {\n    if (burger.id) {\n      localStorage.setItem("burger", JSON.stringify(burger));\n    } else {\n      let localStorageBurger = JSON.parse(localStorage.getItem("burger"));\n      dispatch({ type: "ADD_BURGER", payload: localStorageBurger });\n    }\n\n    for (let i = 0; i < toppings.length; i++) {\n      for (let j = 0; j < burger.consists_of.length; j++) {\n        if (burger.consists_of[j].name === toppings[i].name) {\n          toppings[i].quantity = burger.consists_of[j].quantity;\n        }\n      }\n    }\n\n    if (toppings.length > 0) {\n      dispatch({\n        type: "ADD_BURGER",\n        payload: { ...burger, consists_of: toppings },\n      });\n    }\n  }, [isLoading]);\n\n  const add = (text, num) => {\n    for (let i = 0; i < toppings.length; i++) {\n      if (toppings[i].name === text) {\n        toppings[i].quantity = num;\n      }\n    }\n    dispatch({\n      type: "ADD_BURGER",\n      payload: { ...burger, consists_of: toppings },\n    });\n    localStorage.setItem(\n      "burger",\n      JSON.stringify({ ...burger, consists_of: toppings })\n    );\n  };\n\n  if (!isLoading)\n    return (\n      <Wrapper>\n        <Menu>\n          <MenuTitle>{burger && burger.name}</MenuTitle>\n          <IngridientWrapper>\n            <BurgerIngridients>\n              {burger.consists_of.map(({ name, quantity, id }) => {\n                return (\n                  <Ingridient\n                    key={id}\n                    text={name}\n                    add={add}\n                    initValue={quantity}\n                  />\n                );\n              })}\n            </BurgerIngridients>\n            <BurgerDetails>\n              <DetailsTitle>\n                <span>{burger && burger.name} | \xd1\x96\xd0\xbd\xd1\x84\xd0\xbe\xd1\x80\xd0\xbc\xd0\xb0\xd1\x86\xd1\x96\xd1\x8f</span>{" "}\n                <DetailsButtonContinue\n                  onClick={() => {\n                    dispatch({\n                      type: "ADD_BURGER_BUCKET",\n                      payload: { ...burger, cost: sumOfToppings(burger) },\n                    });\n                    history.push("/bucket");\n                  }}\n                >\n                  \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb4\xd0\xbe\xd0\xb2\xd0\xb6\xd0\xb8\xd1\x82\xd0\xb8\n                </DetailsButtonContinue>\n              </DetailsTitle>\n              <IngridientsDetails>\n                {burger.consists_of\n                  .filter((el) => el.quantity > 0)\n                  .map((el) => {\n                    return (\n                      <IngridientdetailBlock\n                        key={el.id}\n                        text={el.name}\n                        price={el.quantity * el.cost}\n                        qty={el.quantity}\n                      ></IngridientdetailBlock>\n                    );\n                  })}\n              </IngridientsDetails>\n              <Total>\xd0\x97\xd0\xb0\xd0\xb3\xd0\xb0\xd0\xbb\xd0\xbe\xd0\xbc {sumOfToppings(burger)}(\xd0\xb3\xd1\x80\xd0\xbd.)</Total>\n            </BurgerDetails>\n          </IngridientWrapper>\n        </Menu>\n      </Wrapper>\n    );\n\n  if (isLoading) {\n    return <span>loading</span>;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

bac*_*ick 7

Array.prototype.filter不会改变数组,而是创建一个新数组。

所以这:

draftState.burgers.filter(el => el.id !== action.payload)

实际上并没有改变draftState.burgers。但这会:

produce(state, (draftState) => {
  draftState.burgers = draftState.burgers.filter(el => el.id !== action.payload)
})
Run Code Online (Sandbox Code Playgroud)