如何使用 redux、immer、react 从数组中删除元素
How to remove elements from array using redux, immer, react
import produce from "immer";
const initialState = {
isLoading: true,
error: "",
burgers: [],
};
export default function (state = initialState, action) {
switch (action.type) {
case "ADD_BURGER_BUCKET": {
return produce(state, (draftState) => {
if (Array.isArray(action.payload)) {
draftState.burgers.push(...action.payload);
} else {
draftState.burgers.push(action.payload);
}
});
}
case "REMOVE_BURGERS_BUCKET": {
return produce(state, (draftState) => {
draftState.burgers = []
});
}
**case "REMOVE_ONE_BURGER_BUCKET": {
return produce(state, (draftState) => {
console.log(action.payload, draftState.burgers) console.log => 3 Proxy {0: {…}}
draftState.burgers.filter(el => el.id !== action.payload)
})
}** HERE THIS ONE DOES NOT WORK!!!
default:
return state;
}
}
return ( <===== BURGER BUTTON
<Burger
key={burger.id}
text={burger.name}
cost={burger.cost}
onClick={() => {
dispatch({
type: "REMOVE_ONE_BURGER_BUCKET",
payload: burger.id, <=== PASS ID TO REDUCER
}); <==== THIS ONE DOESN'T REMOVE THE ELEMENT FROM AN ARRAY
localStorage.setItem("burger", JSON.stringify(burger));
localStorage.setItem(
"burgersBucket",
JSON.stringify(
list.burgers.filter((el) => el.id !== burger.id)
)
);
history.push("/redo");
}}
/>
);
}
我想通过 id 从数组中删除元素,但我做不到,这就是我在控制台中得到的结果
3 代理 {0: {…}}
我导入了 useselector 和 useDispatch 挂钩。
完整代码
import React from "react";
import { Wrapper } from "../../styled/general";
import { Menu, MenuTitle, Burgers } from "../home/homestyled";
import Burger from "../../component/burger";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
export default function Index() {
const list = useSelector((state) => state.burgerBucket);
const dispatch = useDispatch();
const history = useHistory();
useEffect(() => {
console.log(list.burgers);
if (list.burgers.length > 0) {
localStorage.setItem("burgersBucket", JSON.stringify(list.burgers));
} else {
let burgersBucket = JSON.parse(localStorage.getItem("burgersBucket"));
dispatch({ type: "ADD_BURGER_BUCKET", payload: burgersBucket });
}
}, []);
return (
<Wrapper>
<Menu>
<MenuTitle>My Bucket</MenuTitle>
<Burgers>
{[...list.burgers, { finish: true }, { addMore: true }].map(
(burger) => {
if (burger.addMore) {
return (
<Burger
key={-2}
bg={"lightgreen"}
text={"Додати ще"}
onClick={() => {
history.push("/");
}}
/>
);
}
if (burger.finish) {
return (
<Burger
key={-1}
bg={"#ff5050"}
text={"Завершити"}
onClick={() => {
dispatch({ type: "REMOVE_BURGERS_BUCKET" });
history.push("/");
}}
/>
);
}
return (
<Burger
key={burger.id}
text={burger.name}
cost={burger.cost}
onClick={() => {
dispatch({
type: "REMOVE_ONE_BURGER_BUCKET",
payload: burger.id,
});
localStorage.setItem("burger", JSON.stringify(burger));
localStorage.setItem(
"burgersBucket",
JSON.stringify(
list.burgers.filter((el) => el.id !== burger.id)
)
);
history.push("/redo");
}}
/>
);
}
)}
</Burgers>
</Menu>
</Wrapper>
);
}
enter code here
完整代码缩减器
import produce from "immer";
const initialState = {
isLoading: true,
error: "",
burgers: [],
};
export default function (state = initialState, action) {
switch (action.type) {
case "ADD_BURGER_BUCKET": {
return produce(state, (draftState) => {
if (Array.isArray(action.payload)) {
draftState.burgers.push(...action.payload);
} else {
draftState.burgers.push(action.payload);
}
});
}
case "REMOVE_BURGERS_BUCKET": {
return produce(state, (draftState) => {
draftState.burgers = []
});
}
case "REMOVE_ONE_BURGER_BUCKET": {
return produce(state, (draftState) => {
console.log(action.payload, draftState.burgers)
draftState.burgers.filter(el => el.id !== action.payload)
})
}
default:
return state;
}
}
也许这一个很重要,这是代码(页面),一旦用户单击那个汉堡按钮,我就会被重定向
完整代码
import React, { useEffect, useState, useContext } from "react";
import { Wrapper } from "../../styled/general";
import { Menu, MenuTitle } from "../home/homestyled";
import {
BurgerIngridients,
IngridientWrapper,
BurgerDetails,
DetailsTitle,
IngridientsDetails,
Total,
DetailsButtonContinue,
} from "./burgerredostyled";
import Ingridient from "../../component/Ingridient";
import IngridientdetailBlock from "../../component/IngridientsDetailBlock";
import { useHistory } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { useBurger } from "../../hooks/useBurger";
import { sumOfToppings } from "../../helpers/sum";
export default function Index() {
const burger = useSelector((state) => state.burger);
const [toppings, error, isLoading] = useBurger(
"http://localhost:3000/toppings"
);
const dispatch = useDispatch();
const history = useHistory();
useEffect(() => {
if (burger.id) {
localStorage.setItem("burger", JSON.stringify(burger));
} else {
let localStorageBurger = JSON.parse(localStorage.getItem("burger"));
dispatch({ type: "ADD_BURGER", payload: localStorageBurger });
}
for (let i = 0; i < toppings.length; i++) {
for (let j = 0; j < burger.consists_of.length; j++) {
if (burger.consists_of[j].name === toppings[i].name) {
toppings[i].quantity = burger.consists_of[j].quantity;
}
}
}
if (toppings.length > 0) {
dispatch({
type: "ADD_BURGER",
payload: { ...burger, consists_of: toppings },
});
}
}, [isLoading]);
const add = (text, num) => {
for (let i = 0; i < toppings.length; i++) {
if (toppings[i].name === text) {
toppings[i].quantity = num;
}
}
dispatch({
type: "ADD_BURGER",
payload: { ...burger, consists_of: toppings },
});
localStorage.setItem(
"burger",
JSON.stringify({ ...burger, consists_of: toppings })
);
};
if (!isLoading)
return (
<Wrapper>
<Menu>
<MenuTitle>{burger && burger.name}</MenuTitle>
<IngridientWrapper>
<BurgerIngridients>
{burger.consists_of.map(({ name, quantity, id }) => {
return (
<Ingridient
key={id}
text={name}
add={add}
initValue={quantity}
/>
);
})}
</BurgerIngridients>
<BurgerDetails>
<DetailsTitle>
<span>{burger && burger.name} | інформація</span>{" "}
<DetailsButtonContinue
onClick={() => {
dispatch({
type: "ADD_BURGER_BUCKET",
payload: { ...burger, cost: sumOfToppings(burger) },
});
history.push("/bucket");
}}
>
продовжити
</DetailsButtonContinue>
</DetailsTitle>
<IngridientsDetails>
{burger.consists_of
.filter((el) => el.quantity > 0)
.map((el) => {
return (
<IngridientdetailBlock
key={el.id}
text={el.name}
price={el.quantity * el.cost}
qty={el.quantity}
></IngridientdetailBlock>
);
})}
</IngridientsDetails>
<Total>Загалом {sumOfToppings(burger)}(грн.)</Total>
</BurgerDetails>
</IngridientWrapper>
</Menu>
</Wrapper>
);
if (isLoading) {
return <span>loading</span>;
}
}
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)
})
import produce from "immer";
const initialState = {
isLoading: true,
error: "",
burgers: [],
};
export default function (state = initialState, action) {
switch (action.type) {
case "ADD_BURGER_BUCKET": {
return produce(state, (draftState) => {
if (Array.isArray(action.payload)) {
draftState.burgers.push(...action.payload);
} else {
draftState.burgers.push(action.payload);
}
});
}
case "REMOVE_BURGERS_BUCKET": {
return produce(state, (draftState) => {
draftState.burgers = []
});
}
**case "REMOVE_ONE_BURGER_BUCKET": {
return produce(state, (draftState) => {
console.log(action.payload, draftState.burgers) console.log => 3 Proxy {0: {…}}
draftState.burgers.filter(el => el.id !== action.payload)
})
}** HERE THIS ONE DOES NOT WORK!!!
default:
return state;
}
}
return ( <===== BURGER BUTTON
<Burger
key={burger.id}
text={burger.name}
cost={burger.cost}
onClick={() => {
dispatch({
type: "REMOVE_ONE_BURGER_BUCKET",
payload: burger.id, <=== PASS ID TO REDUCER
}); <==== THIS ONE DOESN'T REMOVE THE ELEMENT FROM AN ARRAY
localStorage.setItem("burger", JSON.stringify(burger));
localStorage.setItem(
"burgersBucket",
JSON.stringify(
list.burgers.filter((el) => el.id !== burger.id)
)
);
history.push("/redo");
}}
/>
);
}
我想通过 id 从数组中删除元素,但我做不到,这就是我在控制台中得到的结果
3 代理 {0: {…}}
我导入了 useselector 和 useDispatch 挂钩。
完整代码
import React from "react";
import { Wrapper } from "../../styled/general";
import { Menu, MenuTitle, Burgers } from "../home/homestyled";
import Burger from "../../component/burger";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
export default function Index() {
const list = useSelector((state) => state.burgerBucket);
const dispatch = useDispatch();
const history = useHistory();
useEffect(() => {
console.log(list.burgers);
if (list.burgers.length > 0) {
localStorage.setItem("burgersBucket", JSON.stringify(list.burgers));
} else {
let burgersBucket = JSON.parse(localStorage.getItem("burgersBucket"));
dispatch({ type: "ADD_BURGER_BUCKET", payload: burgersBucket });
}
}, []);
return (
<Wrapper>
<Menu>
<MenuTitle>My Bucket</MenuTitle>
<Burgers>
{[...list.burgers, { finish: true }, { addMore: true }].map(
(burger) => {
if (burger.addMore) {
return (
<Burger
key={-2}
bg={"lightgreen"}
text={"Додати ще"}
onClick={() => {
history.push("/");
}}
/>
);
}
if (burger.finish) {
return (
<Burger
key={-1}
bg={"#ff5050"}
text={"Завершити"}
onClick={() => {
dispatch({ type: "REMOVE_BURGERS_BUCKET" });
history.push("/");
}}
/>
);
}
return (
<Burger
key={burger.id}
text={burger.name}
cost={burger.cost}
onClick={() => {
dispatch({
type: "REMOVE_ONE_BURGER_BUCKET",
payload: burger.id,
});
localStorage.setItem("burger", JSON.stringify(burger));
localStorage.setItem(
"burgersBucket",
JSON.stringify(
list.burgers.filter((el) => el.id !== burger.id)
)
);
history.push("/redo");
}}
/>
);
}
)}
</Burgers>
</Menu>
</Wrapper>
);
}
enter code here
完整代码缩减器
import produce from "immer";
const initialState = {
isLoading: true,
error: "",
burgers: [],
};
export default function (state = initialState, action) {
switch (action.type) {
case "ADD_BURGER_BUCKET": {
return produce(state, (draftState) => {
if (Array.isArray(action.payload)) {
draftState.burgers.push(...action.payload);
} else {
draftState.burgers.push(action.payload);
}
});
}
case "REMOVE_BURGERS_BUCKET": {
return produce(state, (draftState) => {
draftState.burgers = []
});
}
case "REMOVE_ONE_BURGER_BUCKET": {
return produce(state, (draftState) => {
console.log(action.payload, draftState.burgers)
draftState.burgers.filter(el => el.id !== action.payload)
})
}
default:
return state;
}
}
也许这一个很重要,这是代码(页面),一旦用户单击那个汉堡按钮,我就会被重定向
完整代码
import React, { useEffect, useState, useContext } from "react";
import { Wrapper } from "../../styled/general";
import { Menu, MenuTitle } from "../home/homestyled";
import {
BurgerIngridients,
IngridientWrapper,
BurgerDetails,
DetailsTitle,
IngridientsDetails,
Total,
DetailsButtonContinue,
} from "./burgerredostyled";
import Ingridient from "../../component/Ingridient";
import IngridientdetailBlock from "../../component/IngridientsDetailBlock";
import { useHistory } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { useBurger } from "../../hooks/useBurger";
import { sumOfToppings } from "../../helpers/sum";
export default function Index() {
const burger = useSelector((state) => state.burger);
const [toppings, error, isLoading] = useBurger(
"http://localhost:3000/toppings"
);
const dispatch = useDispatch();
const history = useHistory();
useEffect(() => {
if (burger.id) {
localStorage.setItem("burger", JSON.stringify(burger));
} else {
let localStorageBurger = JSON.parse(localStorage.getItem("burger"));
dispatch({ type: "ADD_BURGER", payload: localStorageBurger });
}
for (let i = 0; i < toppings.length; i++) {
for (let j = 0; j < burger.consists_of.length; j++) {
if (burger.consists_of[j].name === toppings[i].name) {
toppings[i].quantity = burger.consists_of[j].quantity;
}
}
}
if (toppings.length > 0) {
dispatch({
type: "ADD_BURGER",
payload: { ...burger, consists_of: toppings },
});
}
}, [isLoading]);
const add = (text, num) => {
for (let i = 0; i < toppings.length; i++) {
if (toppings[i].name === text) {
toppings[i].quantity = num;
}
}
dispatch({
type: "ADD_BURGER",
payload: { ...burger, consists_of: toppings },
});
localStorage.setItem(
"burger",
JSON.stringify({ ...burger, consists_of: toppings })
);
};
if (!isLoading)
return (
<Wrapper>
<Menu>
<MenuTitle>{burger && burger.name}</MenuTitle>
<IngridientWrapper>
<BurgerIngridients>
{burger.consists_of.map(({ name, quantity, id }) => {
return (
<Ingridient
key={id}
text={name}
add={add}
initValue={quantity}
/>
);
})}
</BurgerIngridients>
<BurgerDetails>
<DetailsTitle>
<span>{burger && burger.name} | інформація</span>{" "}
<DetailsButtonContinue
onClick={() => {
dispatch({
type: "ADD_BURGER_BUCKET",
payload: { ...burger, cost: sumOfToppings(burger) },
});
history.push("/bucket");
}}
>
продовжити
</DetailsButtonContinue>
</DetailsTitle>
<IngridientsDetails>
{burger.consists_of
.filter((el) => el.quantity > 0)
.map((el) => {
return (
<IngridientdetailBlock
key={el.id}
text={el.name}
price={el.quantity * el.cost}
qty={el.quantity}
></IngridientdetailBlock>
);
})}
</IngridientsDetails>
<Total>Загалом {sumOfToppings(burger)}(грн.)</Total>
</BurgerDetails>
</IngridientWrapper>
</Menu>
</Wrapper>
);
if (isLoading) {
return <span>loading</span>;
}
}
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)
})