当我更新费用时,它不会触发useEffect将数据存储在本地存储中。
import React, { useState, useEffect } from 'react';
export const ExpenseContext = React.createContext();
const ExpenseState = (props) => {
const [state, setState] = useState(
() => JSON.parse(localStorage.getItem('expenses')) || []
);
useEffect(() => {
console.log('didUpdate', state)
state.length !== 0 && localStorage.setItem('expenses', JSON.stringify(state));
}, [state])
function addExpense({id, name, category, value, note, date}){
const expense = state.find(exp => exp.id === id);
if(!expense){
setState(state => ([...state, {id, name, category, value, note, date}]))
}else{
const updatedExpense = state.map(exp => {
if(exp.id === expense.id){
return {
...exp,
...{id, name, category, value, note, date}
}
}else{
return exp
}
})
setState(updatedExpense)
}
console.log(state)
}
return (
<ExpenseContext.Provider
value={{
expenses: state,
addExpense: addExpense,
}}
>
{props.children}
</ExpenseContext.Provider>
)
}
我正在为数组的每个元素调用addExpense。假设我们有4个费用存储在存储中。现在,我们更新了一项费用,然后运行以下代码。
for(const expense of expenses){
expenseContext.addExpense(expense);
}
现在,使用效果仅针对最后一个元素触发,费用也不会在上下文中更新。
答案 0 :(得分:0)
您的代码正在运行,我不确定您是否只是缺少一些东西?
1。。export default ExpenseState
丢失了吗?
2。。用ExpenseState
上下文包装您的应用
假设您具有默认的 CRA 设置:
// index.js
import React from "react"
import ReactDOM from "react-dom"
import ExpenseState from "./AppContext" // or where your Context
import App from "./App"
const rootElement = document.getElementById("root")
ReactDOM.render(
<ExpenseState>
<App />
</ExpenseState>,
rootElement
)
和您的 App.js
// App.js
import React, { useContext } from "react"
import { ExpenseContext } from "./AppContext"
export default () => {
const { expenses, addExpense } = useContext(ExpenseContext)
const handleExpense = () => {
addExpense({
id: 1, // Change ID to add another object
name: "some name",
category: "some category", // keep the id and change some values for update
value: "some value",
note: "some note",
date: "some date"
})
}
return (
<div className="App">
<button onClick={handleExpense}>Add Expenses</button>
<pre>
<code>{JSON.stringify(expenses, null, 2)}</code>
</pre>
</div>
)
}
有效的codeSandBox示例。
答案 1 :(得分:0)
问题在于useState
的工作方式与您认为的不同。在使用者内部,您连续三次调用api.addExpense(...)
,同时期望调用setState
会就地更新state
-不会,状态只会更新下一次渲染调用,而不是第40行,因为您的console.log
暗示您期望如此。
因此,除了您期望的三个完整状态更新(每个expense
一个状态更新)之外,您只能从{id: "d6109eb5-9d7b-4cd3-8daa-ee485b08361b", name: "book", category: "personal care", value: 200}
的最新更新中获取状态,该状态没有更改,仍然基于原始状态,而不是第一项的值设置为800的状态。
我建议您修改您的ExpenseState
api以花费一系列费用,以便它可以适当地处理多个内部更新。
function addOrUpdateExpense(state, { id, name, category, value }) {
const expense = state.find(exp => exp.id === id);
if (!expense) {
return [...state, { id, name, category, value }];
} else {
const updatedExpense = state.map(exp => {
if (exp.id === expense.id) {
return {
...exp,
...{ id, name, category, value }
};
} else {
return exp;
}
});
return updatedExpense;
}
}
function addExpenses(expenses) {
let newState = [...state];
for (const expense of expenses) {
newState = addOrUpdateExpense(newState, expense);
}
setState(newState);
}
// ...usage
function doIt() {
api.addExpenses(expenses);
}
这是一个常见的误解,请记住,下一个状态仅在下一个渲染阶段异步可用,将useState
中的状态视为在渲染过程中是不可变的。