用户界面:
我有一个包含四种货币的下拉列表。每次我选择一种新货币时,屏幕上的货币表示形式也会发生变化。当我第一次选择欧元时,我所有的货币标记都变成空白。然后,如果我选择英镑,我的所有货币都会标记为欧元符号的更改。为什么我的状态更改会延迟?
组件/currency.js
import React, { useState,useContext,useEffect } from 'react';import { AppContext } from '../context/AppContext';
const Budget = () => {const [currency, setCurrency] = useState('');const { dispatch } = useContext(AppContext);
const handleChange = (event) => {
setCurrency(event.target.value);
changeCurrency()
};
const changeCurrency = () => {
dispatch({
type: 'CHG_CURRENCY',
payload: currency,
});
}
useEffect(() => {console.log(currency);}, [currency] )
return (
<div className="alert alert-secondary">
<select id="inputGroupSelect02" onChange={handleChange}>
<option defaultValue>Currency</option>
<option value="$" name="dollar">$ Dollar</option>
<option value="£" name="pound">£ Pound</option>
<option value="€" name="euro">€ Euro</option>
<option value="₹" name="ruppee">₹ Ruppee</option>
</select>
</div>
);
export default Budget;
上下文/AppContext.js
import React, { createContext, useReducer } from 'react';
// 5. The reducer - this is used to update the state, based on the action
export const AppReducer = (state, action) => {
let budget = 0;
switch (action.type) {
case 'ADD_EXPENSE':
let total_budget = 0;
total_budget = state.expenses.reduce(
(previousExp, currentExp) => {
return previousExp + currentExp.cost
},0
);
total_budget = total_budget + action.payload.cost;
action.type = "DONE";
if(total_budget <= state.budget) {
total_budget = 0;
state.expenses.map((currentExp)=> {
if(currentExp.name === action.payload.name) {
currentExp.cost = action.payload.cost + currentExp.cost;
}
return currentExp
});
return {
...state,
};
} else {
alert("Cannot increase the allocation! Out of funds");
return {
...state
}
}
case 'RED_EXPENSE':
const red_expenses = state.expenses.map((currentExp)=> {
if (currentExp.name === action.payload.name && currentExp.cost - action.payload.cost >= 0) {
currentExp.cost = currentExp.cost - action.payload.cost;
budget = state.budget + action.payload.cost
}
return currentExp
})
action.type = "DONE";
return {
...state,
expenses: [...red_expenses],
};
case 'DELETE_EXPENSE':
action.type = "DONE";
state.expenses.map((currentExp)=> {
if (currentExp.name === action.payload) {
budget = state.budget + currentExp.cost
currentExp.cost = 0;
}
return currentExp
})
action.type = "DONE";
return {
...state,
budget
};
case 'SET_BUDGET':
action.type = "DONE";
state.budget = action.payload;
return {
...state,
};
case 'CHG_CURRENCY':
action.type = "DONE";
state.currency = action.payload;
return {
...state
}
default:
return state;
}
};
// 1. Sets the initial state when the app loads
const initialState = {
budget: 2000,
expenses: [
{ id: "Marketing", name: 'Marketing', cost: 50 },
{ id: "Finance", name: 'Finance', cost: 300 },
{ id: "Sales", name: 'Sales', cost: 70 },
{ id: "Human Resource", name: 'Human Resource', cost: 40 },
{ id: "IT", name: 'IT', cost: 500 },
],
currency: '£'
};
// 2. Creates the context this is the thing our components import and use to get the state
export const AppContext = createContext();
// 3. Provider component - wraps the components we want to give access to the state
// Accepts the children, which are the nested(wrapped) components
export const AppProvider = (props) => {
// 4. Sets up the app state. takes a reducer, and an initial state
const [state, dispatch] = useReducer(AppReducer, initialState);
let remaining = 0;
if (state.expenses) {
const totalExpenses = state.expenses.reduce((total, item) => {
return (total = total + item.cost);
}, 0);
remaining = state.budget - totalExpenses;
}
return (
<AppContext.Provider
value={{
expenses: state.expenses,
budget: state.budget,
remaining: remaining,
dispatch,
currency: state.currency
}}
>
{props.children}
</AppContext.Provider>
);
};
到目前为止已使用组件
import React, { useContext } from 'react';
import { AppContext } from '../context/AppContext';
const ExpenseTotal = () => {
const { expenses,currency } = useContext(AppContext);
const totalExpenses = expenses.reduce((total, item) => {
return (total += item.cost);
}, 0);
return (
<div className='alert alert-primary'>
<span>Spent so far: {currency}{totalExpenses}</span>
</div>
);
};
export default ExpenseTotal;
将
changeCurrency()
放入 useEffectHook 中。
发生这种情况是因为当您调用
setCurrency
来更新状态时,它不会立即更新状态,而是将其放入队列中,直到当前运行堆栈变空时才会生效。因此,您不会立即更新货币状态。
我建议你看看这个 React 文档 这将详细描述为什么会发生这种情况
你是如何添加标签的? ):我迷路了