useSelector在reduxjs/toolkit中未更新状态。

huangapple go评论90阅读模式
英文:

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) =&gt; {
  console.log(&quot;priceInSendRequestFunction = &quot;, price);
};

const priceHandler = event =&gt; {
  const { value } = event.target;
  const newPrice = value || &quot;any&quot;;

  console.log({ newPrice });
  dispatch(userActions.changePrice(newPrice));

  sendRequest(newPrice);
};

Or you can import the store and access the current state directly:

import store from &#39;../path/to/store&#39;;

...

const sendRequest = async () =&gt; {
  const state = store.getState();
  const { price } = state.user;

  console.log(&quot;priceInSendRequestFunction = &quot;, price);
};

const priceHandler = event =&gt; {
  const { value } = event.target;
  const newPrice = value || &quot;any&quot;;

  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 &#39;@reduxjs/toolkit&#39;;

const initialUserState = {
  isLoggedIn: !!localStorage.getItem(&quot;token&quot;),
  carName: &quot;&quot;,
  price: &quot;any&quot;,
  avaliablity: &quot;any&quot;,
  type: &quot;any&quot;
};

export const changePrice = createAsyncThunk(
  &quot;user/changePrice&quot;,
  async (price, thunkAPI) =&gt; {
    console.log(&quot;price in changePrice action = &quot;, price);
    try {
      // side-effect to send price ...somewhere
      ...
      return price;
    } catch(error) {
      return thunkAPI.rejectWithValue(error);
    }
  }
);

const userSlice = createSlice({
  name: &quot;user&quot;,
  initialState: initialUserState,
  reducers: {
    handleAuthState: state =&gt; {
      state.isLoggedIn = !!localStorage.getItem(&quot;token&quot;);
    },
    changeCarName: (state, action) =&gt; {
      state.carName = action.payload;
    },
    changeAvailablity: (state, action) =&gt; {
      state.avaliablity = action.payload;
    },
    changeType: (state, action) =&gt; {
      state.type = action.payload;
    },
  },
  extraReducers: builder =&gt; {
    builder
      // Update local price state if side-effect successful
      .addCase(changePrice.fulfilled, (state, action) =&gt; {
        state.price = action.payload;
      });
  },
});
const Filters = () =&gt; {
  const dispatch = useDispatch();

  const {
    availablity,
    carName,
    price,
    type,
  } = useSelector(state =&gt; state.user);

  const priceHandler = event =&gt; {
    const { value } = event.target;
    const newPrice = value || &quot;any&quot;;

    console.log({ newPrice });
    dispatch(userActions.changePrice(newPrice));
  }

  return (
    &lt;Select onChange={priceHandler} placeholder=&quot;Select Price&quot;&gt;
      &lt;option value=&quot;2000&quot;&gt;Below 2000&lt;/option&gt;
      &lt;option value=&quot;4000&quot;&gt;2000 - 4000&lt;/option&gt;
      &lt;option value=&quot;6000&quot;&gt;4000 - 6000&lt;/option&gt;
      &lt;option value=&quot;infinity&quot;&gt;Above 6000&lt;/option&gt;
      &lt;option value=&quot;any&quot;&gt;Any&lt;/option&gt;
    &lt;/Select&gt;
  )
}

huangapple
  • 本文由 发表于 2023年3月9日 14:52:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75681289.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定