【问题标题】:In my React app, why isn't this Redux reducer executed?在我的 React 应用程序中,为什么没有执行这个 Redux reducer?
【发布时间】:2021-01-06 03:24:37
【问题描述】:

下午好,

在完成了 React 教程并阅读了所有 React 指南之后,我完成了 Redux 教程来重写我的工作身份验证组件以使用 Redux 而不是组件状态(我也从类切换到功能组件)。

我的 Redux 设置如下:

import { createSlice } from '@reduxjs/toolkit';

const sessionInitialState = {
        authToken: null,
        userLogin: null,
    };

export const sessionSlice = createSlice({
  name: 'session',
  initialState: {
    value: sessionInitialState,
  },
  reducers: {
    sessionRegister: (state, action) => {
      console.log("Storing:")
      console.log(action.payload)
      state.value = action.payload;
    },
    sessionDestroy: state => {
      console.log("Destroying session")
      state.value = sessionInitialState;
      localStorage.removeItem("sessionData");
    },
  },
});

export const { sessionRegister, sessionDestroy } = sessionSlice.actions;
export const selectSession = state => state.session.value;

export default sessionSlice.reducer;

在我的登录组件中,我将身份验证令牌和用户名存储如下:

// [...]
import { useDispatch } from 'react-redux';
import { sessionRegister } from './SessionSlice';
// [...]

function LoginForm(props) {
    const dispatch = useDispatch();
    function onFormSubmit(event) {
        // [...] This is when API response code is 200:
        
                let sessionData = {
                        authToken: response.data.token,
                        userLogin: userName,
                }
                localStorage.setItem("sessionData", JSON.stringify(sessionData));
                console.log("Stored:" + localStorage.getItem("sessionData"));
                setApiError(null);
                dispatch(sessionRegister(sessionData));

如果 Redux 中没有存储数据,我的 App 组件会显示登录表单,如果存在则显示用户名和令牌:

function App(props) {

    const sessionData = useSelector(selectSession);
    const storedSessionData = localStorage.getItem("sessionData");
    
    if (storedSessionData && !sessionData.authToken) {
        console.log("App init check. Storing :");
        console.log(JSON.parse(storedSessionData));
        sessionRegister(JSON.parse(storedSessionData));
    } else {
        if (!storedSessionData) console.log("No sessionData and no stored data");
    }

    return (
        <div className="App">
            <div className="topbar"><Topbar /></div>
            <div className="content">
            {sessionData.authToken ? (
                    <span>User: {sessionData.userLogin} {storedSessionData}</span>
                ) : (
                    <LoginForm />
                )
            }
            </div>
        </div>
    );
}

这一切几乎都奏效了。登录组件在 API 调用之后通过 Redux 存储数据,并且也在 localStorage 中。来自 Redux 的 userLogin 由 App 显示,localStorage 内容也显示。但是如果我刷新页面,应用程序会从 locaStorage 获取数据,但不会调用 sessionRegister(或什么都不做)。

它发生如下:

第一次打开页面。控制台:No sessionData and no stored data
通过 LoginForm 登录。控制台:

Localy stored:{"authToken":"5467c25e000df49a1161c4ff8ga1f610053f62b8","userLogin":"testuser"} 
Storing in Redux:
Object { authToken: "5467c25e000df49a1161c4ff8ga1f610053f62b8", userLogin: "testuser" }

现在 App 组件正确地呈现内容而不是登录表单:

User: testuser {"authToken":"5467c25e000df49a1161c4ff8ga1f610053f62b8","userLogin":"testuser"}

到目前为止,一切都很好。但是如果我刷新页面,登录表单会再次显示。在控制台中我得到:

App init check. Storing : App.js:15
Object { authToken: "5467c25e000df49a1161c4ff8ga1f610053f62b8", userLogin: "testuser" } App.js:16
App init check. Storing : App.js:15
Object { authToken: "5467c25e000df49a1161c4ff8ga1f610053f62b8", userLogin: "testuser" } App.js:16

我不明白为什么sessionRegister(JSON.parse(storedSessionData));没有正确执行,为什么我得到两次控制台日志App init check

感谢您阅读所有这些内容,我们将不胜感激。

【问题讨论】:

    标签: reactjs redux


    【解决方案1】:

    我认为你错过了一个调度

    而不是

    sessionRegister(JSON.parse(storedSessionData));
    

    应该是

    dispatch(sessionRegister(JSON.parse(storedSessionData)));
    

    在您的 App 组件中。你可以通过钩子访问dispatch

    const dispatch = useDispatch()
    

    最后但并非最不重要的一点是,您在每次渲染中都会更新存储,这就是为什么您会看到两次日志的原因。我认为您应该将其移至效果器

    const dispatch = useDispatch()
    const sessionData = useSelector(selectSession);
    useEffect(() => {
      const storedSessionData = localStorage.getItem("sessionData");
      if (storedSessionData && !sessionData.authToken) {
          console.log("App init check. Storing :");
          console.log(JSON.parse(storedSessionData));
          sessionRegister(JSON.parse(storedSessionData));
      } else {
          if (!storedSessionData) console.log("No sessionData and no stored data");
      }
    }, [dispatch, sessionData])
    

    【讨论】:

    • 非常感谢 Gonzalo.- !你让我开心,我没有错过 useDispatch :) useEffect 的使用很好,虽然它让登录表单出现了很短的时间
    • 试试 useLayoutEffect 而不是 useEffect。您可能还想将此效果移动到应用程序的父级 - 因此您可以在渲染应用程序之前等待效果执行(同时显示微调器或其他内容)
    猜你喜欢
    • 1970-01-01
    • 2020-05-23
    • 2018-08-14
    • 1970-01-01
    • 1970-01-01
    • 2020-01-16
    • 2019-12-05
    • 2022-11-07
    • 2019-05-16
    相关资源
    最近更新 更多