在渲染之前加载状态/数据?

时间:2020-10-08 16:27:11

标签: reactjs react-redux mern

我已经实现了我的应用程序的身份验证部分(使用MERN堆栈构建)。登录操作将验证登录数据,然后加载用户数据,然后将路由推送到/dashboard。在仪表板页面上,我有一个简单的Welcome to the dashboard, {email}!,但是我收到一条错误消息,告诉它它不能返回null数据。我在导航栏中也有用户的名字和姓氏以及他们的电子邮件,这也产生了返回空数据的错误。我有一个useEffect可以将用户数据加载到App.js中,但是我仍然收到null错误。

是否可以在渲染之前加载数据?

Index.js

ReactDOM.render(
  <Provider store={store}>
    <PersistGate loading={null} persistor={persistor}>
      <ConnectedRouter history={history}>
        <App />
      </ConnectedRouter>
    </PersistGate>
  </Provider>,
  document.getElementById('root')
);

App.js

const App = () => {
  const [loading, setLoading] = useState(true);
  const dispatch = useDispatch();

  useEffect(() => {
    // check for token in LS
    if (localStorage.token) {
      setAuthToken(localStorage.token);
    }
    dispatch(attemptGetUser())
      .then(() => setLoading(false))
      .catch(() => setLoading(false));

    // Logout user from all tabs if they logout in another tab
    window.addEventListener('storage', () => {
      if (!localStorage.token) dispatch({ type: LOGOUT });
    });

    // eslint-disable-next-line
  }, []);

  return loading ? (
    <Loading cover="page" />
  ) : (
    <div className="App">
      <Switch>
        <Route path="/" component={Views} />
      </Switch>
    </div>
  );
};

redux / thunks / Auth.js

export const attemptLogin = (formData) => async (dispatch) => {
  await postLogin(formData)
    .then((res) => {
      dispatch(login(res.data));
      dispatch(push('/dashboard'));
    })
    .then(() => {
      dispatch(attemptGetUser());
    })
    .catch((error) => {
      const errors = error.response.data.message;
      dispatch(setAlert('Uh-oh!', errors, 'error'));
    });
};

redux / thunks / User.js

export const attemptGetUser = () => async (dispatch) => {
  await getUser()
    .then((res) => {
      dispatch(setUser(res.data));
    })
    .catch((error) => {
      const errors = error.response.data.message;
      console.log(errors);
      dispatch(setAlert('Uh-oh!', errors, 'danger'));
    });
};

视图/应用程序视图/仪表板

const Dashboard = () => {
  const { email } = useSelector((state) => state.user.user);
  return (
    <div>
      Welcome to the dashboard,
      <strong>{email}</strong>!
    </div>
  );
};

export default Dashboard;

components / layout-components / NavProfile.js

export const NavProfile = () => {
  const { firstName, lastName, email } = useSelector(
    (state) => state.user.user
  );

  const dispatch = useDispatch();

  const onLogout = () => {
    dispatch(attemptLogout());
  };

  const profileImg = '/img/avatars/thumb-1.jpg';
  const profileMenu = (
    <div className="nav-profile nav-dropdown">
      <div className="nav-profile-header">
        <div className="d-flex">
          <Avatar size={45} src={profileImg} />
          <div className="pl-3">
            <h4 className="mb-0">{firstName} {lastName}</h4>
            <span className="text-muted">{email}</span>
          </div>
        </div>
      </div>
      <div className="nav-profile-body">
        <Menu>
          {menuItem.map((el, i) => {
            return (
              <Menu.Item key={i}>
                <a href={el.path}>
                  <Icon className="mr-3" type={el.icon} />
                  <span className="font-weight-normal">{el.title}</span>
                </a>
              </Menu.Item>
            );
          })}
          <Menu.Item key={menuItem.legth + 1} onClick={onLogout}>
            <span>
              <LogoutOutlined className="mr-3" />
              <span className="font-weight-normal">Logout</span>
            </span>
          </Menu.Item>
        </Menu>
      </div>
    </div>
  );
  return (
    <Dropdown placement="bottomRight" overlay={profileMenu} trigger={['click']}>
      <Menu className="d-flex align-item-center" mode="horizontal">
        <Menu.Item>
          <Avatar src={profileImg} />
        </Menu.Item>
      </Menu>
    </Dropdown>
  );
};

export default NavProfile;

2 个答案:

答案 0 :(得分:1)

所以错误告诉您在redux状态下state.user.user是未定义的,这就是为什么您无法解构firstNamelastNameemail值的原因。

如果您商店中的state.user.user至少是一个已定义的空对象({}),则应该解决对空错误的访问。

const userReducer = (state = { user: {} }, action) => {
  ...
}

这仍然可能使UI呈现为“未定义”,因此在组件代码中,您需要提供默认值,即

const { firstName = '', lastName = '', email = '' } = useSelector(
  (state) => state.user.user
);

另一种方法是在用户化简器切片中具有完全限定的初始状态。

const initialState = {
  user: {
    firstName: '',
    lastName: '',
    email: '',
  },
};

const userReducer = (state = initialState, action) => {
  ...
}

答案 1 :(得分:0)

似乎您可以通过更改Redux存储的初始状态来解决此问题。

以您的仪表板组件为例:

const Dashboard = () => {
  const { email } = useSelector((state) => state.user.user);
  return (
    <div>
      Welcome to the dashboard,
      <strong>{email}</strong>!
    </div>
  );
};

它期望Redux存储中的用户状态片中存在一个带有电子邮件字符串的用户对象。为noted in their documentation

您可以更新您的createStore调用以包括Redux存储的初始值,例如createStore({'user': {'user': {'email': ''}}});