Redux toolkit userSlice需要刷新才能从本地存储访问数据

pqwbnv8z  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(146)

我使用Redux Toolkit(RTK)Query进行API调用,使用RTK进行状态管理。我面临的问题是,每次登录时,我从后端获得的用户信息不会从localStorage自动更新,并且需要在userSlice中访问数据之前刷新一次。我使用extraReducers自动从userLogin端点获取数据并将其存储在localStorage中。我再次访问localStorage数据并将其作为userSlice的初始状态提供。
这是我的User Slice。

import { createSlice } from "@reduxjs/toolkit";
import Apiservice from "../service/apiService";

const initialState = {
  userInfo: localStorage.getItem("userInfo")
    ? JSON.parse(localStorage.getItem("userInfo"))
    : null,
};

const userSlice = createSlice({
  name: "userSlice",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder.addMatcher(
      Apiservice.endpoints.userLogin.matchFulfilled,
      (state, action) => {
        localStorage.setItem("userInfo", JSON.stringify(action.payload));
      }
    );

    builder.addMatcher(
      Apiservice.endpoints.getMyDetails.matchFulfilled,
      (state, action) => {
        localStorage.setItem("userInfo", JSON.stringify(action.payload));
      }
    );
  },
});

export const {} = userSlice.actions;

export default userSlice.reducer;

这是Login组件,我需要手动调用window.location.reload()-不这样做将不会给我从userSliceuserInfo数据。

const Login = () => {
  const [showPass, setShowPass] = useState(false);
  const [showPass1, setShowPass1] = useState(false);

  const {
    control,
    watch,
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    defaultValues: {
      email: "",
      password: "",
    },
  });
  const toast = useToast();
  const navigate = useNavigate();

  const email = watch("email");
  const password = watch("password");

  const [userLogin, { isLoading, isError, isSuccess, error, data }] =
    useUserLoginMutation();

  useEffect(() => {
    if (isSuccess) {
      toast({
        title: "Login Successful.",
        status: "success",
        duration: 9000,
        isClosable: true,
      });
      navigate("/");
      window.location.reload();
    }
    if (isError) {
      toast({
        title: error?.data?.message,
        status: "error",
        duration: 5000,
        isClosable: true,
      });
    }
  }, [isSuccess, toast, navigate, isError, error?.data]);

  const onSubmit = (data) => {
    userLogin(data);
  };

  ...

当我第一次登录userInfo时,我使用useSelector获得的数据是空的,一旦刷新,就会用localStorage数据填充。
我假设redux store存储/检索信息的方式是异步的,但我对应该采用哪种方法感到困惑。还有,当有一个api调用更新用户信息时该怎么办?我也应该在每次发生这种情况时刷新吗?

f8rj6qna

f8rj6qna1#

你似乎对几个关键概念有点误解:

  1. Reducer函数不是用来发布副作用的,它们应该是纯函数,使用当前状态值和动作,并返回下一个状态值。
  2. LocalStorage是非React性的,更新它不会神奇地触发React应用程序重新渲染或重新加载自己***只是这样它就可以从localStorage中提取值。更新应用程序状态中的真相来源。
    现在忽略状态持久性,reducer函数应该只使用您希望状态具有的值来更新状态。当状态更新时,这将触发订阅的(
    到该状态 )组件重新呈现并接收
    当前***userInfo状态值。
    示例:
const initialState = {
  userInfo: localStorage.getItem("userInfo")
    ? JSON.parse(localStorage.getItem("userInfo"))
    : null,
};

const userSlice = createSlice({
  name: "userSlice",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addMatcher(
        Apiservice.endpoints.userLogin.matchFulfilled,
        (state, action) => {
          state.userInfo = action.payload;
        }
      )
      .addMatcher(
        Apiservice.endpoints.getMyDetails.matchFulfilled,
        (state, action) => {
          state.userInfo = action.payload;
        }
      );
  },
});

在紧要关头,你当然可以从reducer函数中更新localStorage,但这会被许多人认为是反模式的,应该尽可能避免。

const userSlice = createSlice({
  name: "userSlice",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addMatcher(
        Apiservice.endpoints.userLogin.matchFulfilled,
        (state, action) => {
          state.userInfo = action.payload;
          localStorage.setItem("userInfo", JSON.stringify(action.payload));
        }
      )
      .addMatcher(
        Apiservice.endpoints.getMyDetails.matchFulfilled,
        (state, action) => {
          state.userInfo = action.payload;
          localStorage.setItem("userInfo", JSON.stringify(action.payload));
        }
      );
  },
});

最好是从一个动作中发出副作用,例如:在API切片的查询/变化的onQueryStarted属性中,或者简单地集成一个redux状态持久化解决方案/库,如redux-persist(* 另请参阅持久化和再水合 *)。

相关问题