英文:
useSelector is not updating the state in reduxjs/toolkit
问题
我试图使用reduxjs/toolkit
来更新state.user.price
状态到其他值,但它没有正常工作。我知道这与不可变性有关,然后我尝试返回新的对象而不改变它们,但它没有起作用。
在sendRequest
函数中,price
的值应该得到更新,但它得到了另一个值。
英文:
I am trying to update the state.user.price
state to some other value using reduxjs/toolkit
but it is not working properly. I know this has to do with immutablity then I tried returning new objects without changing them but it didn't work.
const initialUserState = {
isLoggedIn: !!localStorage.getItem("token"),
carName: "",
price: "any",
avaliablity: "any",
type: "any"
}
const userSlice = createSlice({
name: "user",
initialState: initialUserState,
reducers: {
handleAuthState: state => {
state.isLoggedIn = !!localStorage.getItem("token");
},
changeCarName: (state, action) => {
state.carName = action.payload;
},
changeAvailablity: (state, action) => {
state.avaliablity = action.payload;
},
changeType: (state, action) => {
state.type = action.payload;
},
changePrice: (state, action) => {
state.price = action.payload;
}
}
});
const store = configureStore({
reducer: {
UI: UISlice.reducer,
user: userSlice.reducer,
car: carSlice.reducer
}
});
export default store;
export const userActions = userSlice.actions;
const Filters = () => {
const type = useSelector(state => state.user.type);
const price = useSelector(state => state.user.price);
const carName = useSelector(state => state.user.carName);
const availablity = useSelector(state => state.user.availablity);
const sendRequest = async () => {
console.log("priceInSendRequestFunction = ", price);
}
const priceHandler = event => {
if (event.target.value === "") {
dispatch(userActions.changePrice("any"))
} else {
console.log("event.target.value = ", event.target.value);
dispatch(userActions.changePrice(event.target.value));
}
sendRequest();
}
return (
<Select onChange={priceHandler} placeholder="Select Price">
<option value="2000">Below 2000</option>
<option value="4000">2000 - 4000</option>
<option value="6000">4000 - 6000</option>
<option value="infinity">Above 6000</option>
<option value="any">Any</option>
</Select>
)
}
The value of price
in sendRequest
function should get the updated value but it is getting another value.
答案1
得分: 2
当前选择的 price
状态在调用 priceHandler
时会在回调范围内闭合。priceHandler
分发一个操作到 store 并立即调用 sendRequest
。组件尚未重新渲染并访问任何更新的 Redux 状态值。
你可以将要更新状态的值传递给 sendRequest
函数:
const sendRequest = async (price) => {
console.log("priceInSendRequestFunction = ", price);
};
const priceHandler = event => {
const { value } = event.target;
const newPrice = value || "any";
console.log({ newPrice });
dispatch(userActions.changePrice(newPrice));
sendRequest(newPrice);
};
或者你可以导入 store
并直接访问当前状态:
import store from '../path/to/store';
...
const sendRequest = async () => {
const state = store.getState();
const { price } = state.user;
consolesole.log("priceInSendRequestFunction = ", price);
};
const priceHandler = event => {
const { value } = event.target;
const newPrice = value || "any";
console.log({ newPrice });
dispatch(userActions.changePrice(newPrice));
sendRequest();
};
如果 sendRequest
函数/逻辑实际上是一个 "副作用",那么另一种选择可能是将 changePrice
操作转换为异步操作,例如一个 Thunk。
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
const initialUserState = {
isLoggedIn: !!localStorage.getItem("token"),
carName: "",
price: "any",
avaliablity: "any",
type: "any"
};
export const changePrice = createAsyncThunk(
"user/changePrice",
async (price, thunkAPI) => {
console.log("price in changePrice action = ", price);
try {
// 发送价格的副作用 ...到某个地方
...
return price;
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
}
);
const userSlice = createSlice({
name: "user",
initialState: initialUserState,
reducers: {
handleAuthState: state => {
state.isLoggedIn = !!localStorage.getItem("token");
},
changeCarName: (state, action) => {
state.carName = action.payload;
},
changeAvailablity: (state, action) => {
state.avaliablity = action.payload;
},
changeType: (state, action) => {
state.type = action.payload;
},
},
extraReducers: builder => {
builder
// 如果副作用成功,更新本地价格状态
.addCase(changePrice.fulfilled, (state, action) => {
state.price = action.payload;
});
},
});
const Filters = () => {
const dispatch = useDispatch();
const {
availablity,
carName,
price,
type,
} = useSelector(state => state.user);
const priceHandler = event => {
const { value } = event.target;
const newPrice = value || "any";
console.log({ newPrice });
dispatch(userActions.changePrice(newPrice));
}
return (
<Select onChange={priceHandler} placeholder="Select Price">
<option value="2000">Below 2000</option>
<option value="4000">2000 - 4000</option>
<option value="6000">4000 - 6000</option>
<option value="infinity">Above 6000</option>
<option value="any">Any</option>
</Select>
)
}
英文:
The current selected price
state is closed over in callback scope when priceHandler
is called. priceHandler
dispatches an action to the store and immediately calls sendRequest
. The component has yet to rerender and access any updated Redux state values.
You can forward the value to sendRequest
that you are updating the state to:
const sendRequest = async (price) => {
console.log("priceInSendRequestFunction = ", price);
};
const priceHandler = event => {
const { value } = event.target;
const newPrice = value || "any";
console.log({ newPrice });
dispatch(userActions.changePrice(newPrice));
sendRequest(newPrice);
};
Or you can import the store
and access the current state directly:
import store from '../path/to/store';
...
const sendRequest = async () => {
const state = store.getState();
const { price } = state.user;
console.log("priceInSendRequestFunction = ", price);
};
const priceHandler = event => {
const { value } = event.target;
const newPrice = value || "any";
console.log({ newPrice });
dispatch(userActions.changePrice(newPrice));
sendRequest();
};
If the sendRequest
function/logic is effectively a "side-effect" then an alternative might be to convert the changePrice
action into an asynchronous action, e.g. a Thunk.
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
const initialUserState = {
isLoggedIn: !!localStorage.getItem("token"),
carName: "",
price: "any",
avaliablity: "any",
type: "any"
};
export const changePrice = createAsyncThunk(
"user/changePrice",
async (price, thunkAPI) => {
console.log("price in changePrice action = ", price);
try {
// side-effect to send price ...somewhere
...
return price;
} catch(error) {
return thunkAPI.rejectWithValue(error);
}
}
);
const userSlice = createSlice({
name: "user",
initialState: initialUserState,
reducers: {
handleAuthState: state => {
state.isLoggedIn = !!localStorage.getItem("token");
},
changeCarName: (state, action) => {
state.carName = action.payload;
},
changeAvailablity: (state, action) => {
state.avaliablity = action.payload;
},
changeType: (state, action) => {
state.type = action.payload;
},
},
extraReducers: builder => {
builder
// Update local price state if side-effect successful
.addCase(changePrice.fulfilled, (state, action) => {
state.price = action.payload;
});
},
});
const Filters = () => {
const dispatch = useDispatch();
const {
availablity,
carName,
price,
type,
} = useSelector(state => state.user);
const priceHandler = event => {
const { value } = event.target;
const newPrice = value || "any";
console.log({ newPrice });
dispatch(userActions.changePrice(newPrice));
}
return (
<Select onChange={priceHandler} placeholder="Select Price">
<option value="2000">Below 2000</option>
<option value="4000">2000 - 4000</option>
<option value="6000">4000 - 6000</option>
<option value="infinity">Above 6000</option>
<option value="any">Any</option>
</Select>
)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论