1

我想在展示组件中访问 Redux Store State,但状态未定义。我制作了 Container Component、Presentational Component 和 Redux Store。

所以我尝试访问user演示组件,但user未定义。

我在为异步 API 请求创建 Redux Store 时使用 Redux-Thunk。

令人怀疑的部分是 Rdux Store State 有一个值,但我无法访问user演示组件中的状态

// headerState.js

import { handleActions } from 'redux-actions';
import * as api from '../lib/api';

const USER_STATE = 'headerState/USER_STATE';
const USER_STATE_SUCCESS = 'headerState/USER_STATE_SUCCESS';
const USER_STATE_FAILURE = 'headerState/USER_STATE_FAILURE';

const USER_LOGOUT = 'headerState/USER_LOGOUT';
const USER_LOGOUT_SUCCESS = 'headerState/USER_LOGOUT_SUCCESS';
const USER_LOGOUT_FAILURE = 'headerState/USER_LOGOUT_FAILURE';

export const getUserInfo = () => async (dispatch) => {
  dispatch({ type: USER_STATE });
  try {
    const response = await api.getUser();
    dispatch({
      type: USER_STATE_SUCCESS,
      payload: response.data,
    });
  } catch (error) {
    dispatch({
      type: USER_STATE_FAILURE,
      payload: error,
      error: true,
    });
    throw error;
  }
};

export const userLogout = () => async (dispatch) => {
  dispatch({ type: USER_LOGOUT });
  try {
    const response = await api.logout();
    dispatch({
      type: USER_LOGOUT_SUCCESS,
      payload: response.data,
    });
  } catch (error) {
    dispatch({
      type: USER_LOGOUT_FAILURE,
      payload: error,
      error: true,
    });
    throw error;
  }
};

const initialState = {
  user: null,
  loading: {
    isProcessing: false,
  },
};

const headerState = handleActions(
  {
    [USER_STATE]: (state) => ({
      ...state,
      loading: {
        ...state.loading,
        isProcessing: true,
      },
    }),
    [USER_STATE_SUCCESS]: (state, action) => ({
      ...state,
      user: action.payload,
      loading: {
        ...state.loading,
        isProcessing: false,
      },
    }),
    [USER_STATE_FAILURE]: (state) => ({
      ...state,
      loading: {
        ...state.loading,
        isProcessing: false,
      },
    }),
    [USER_LOGOUT]: (state) => ({
      ...state,
      loading: {
        ...state.loading,
        isProcessing: true,
      },
    }),
    [USER_LOGOUT_SUCCESS]: (state, action) => ({
      ...state,
      user: action.payload,
      loading: {
        ...state.loading,
        isProcessing: false,
      },
    }),
    [USER_LOGOUT_FAILURE]: (state) => ({
      ...state,
      loading: {
        ...state.loading,
        isProcessing: false,
      },
    }),
  },
  initialState,
);

export default headerState;

// HeaderContainer.js

import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import Header from './common/Header';
import { getUserInfo, userLogout } from '../modules/headerState';

const HeaderContainer = ({ user, getUserInfo, userLogout }) => {
  useEffect(() => {
    getUserInfo();
  }, [getUserInfo]);

  return <Header user={user} logout={userLogout} />;
};

const mapStateToProps = (state) => {
  return {
    user: state.user,
    loading: state.loading,
  };
};

export default connect(mapStateToProps, {
  getUserInfo,
  userLogout,
})(HeaderContainer);

// Header.js

(...)

const Header = ({ user, logout }) => {  ** // user is undefined **
  return (
    <>
      <TopNav>
        <Link to="/" style={TitleLinkStyle}>
          <NavTitle>
            <img
              src={logo}
              width="50"
              height="50"
              color="white"
              style={{ paddingRight: '25px', alignSelf: 'center' }}
              alt="logo"
            />
            Service Title
          </NavTitle>
        </Link>
        <div style={{ display: 'flex', flex: 4 }} />
        <SubNav>
          <Link to="/home" style={{ textDecoration: 'none', color: 'white' }}>
            <HomeDiv>Home</HomeDiv>
          </Link>
          {!user.snsId && (
            <Link
              to="/login"
              style={{ textDecoration: 'none', color: 'white' }}
            >
              <LoginDiv>Login</LoginDiv>
            </Link>
          )}
          {user.snsId && (
            <LoginDiv onClick={logout} style={{ cursor: 'pointer' }}>
              Logout
            </LoginDiv>
          )}
        </SubNav>
      </TopNav>
    </>
  );
};

export default Header;

4

1 回答 1

0

有两个潜在的问题。

首先, 的初始值为usernull,直到USER_STATE_SUCCESS被调度。所以试图user.snsId在你的演示组件中访问会导致类型错误:

无法读取未定义的属性“snsId”

您可以使用可选链接来尝试访问snsId和简化您的逻辑。

// Header.js
const Header = ({ user }) => {
  return user?.snsId ? <div>Logout</div> : <div>Login</div>;
};

第二个问题可能在于您如何创建和访问您的商店。我假设你正在做这样的事情:

const reducers = combineReducers({
  header: headerReducer
});
const store = createStore(reducers);

使用时mapStateToProps,您的容器组件需要通过创建它时使用的相同键来访问该状态切片 - header.

// HeaderContainer.js
const mapStateToProps = (state) => {
  return {
    user: state.header.user, // state.user is undefined
    loading: state.header.loading // state.loading is undefined
  };
};

编辑 serene-booth-z4x4u

于 2021-08-04T00:46:08.667 回答