在渲染之前加载 state/data?
Load state/data before render?
我已经实现了我的应用程序的身份验证部分(使用 MERN 堆栈构建)。登录操作验证登录数据,然后加载用户数据,然后将路由推送到 /dashboard
。在仪表板页面上,我有一个简单的 Welcome to the dashboard, {email}!
但是我收到一条错误消息,告诉我它不能 return 空数据。我还在导航栏中有用户的名字和姓氏以及他们的电子邮件,这也会产生 returning 空数据的错误。我有一个 useEffect 可以在我的 App.js
中加载用户数据,但我仍然收到空错误。
有没有办法在渲染之前加载数据?
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'));
});
};
views/app-views/dashboard
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;
看来您可以通过更改 Redux 存储初始状态来解决此问题。
以您的 Dashboard 组件为例:
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': ''}}});
所以错误告诉你,在你的 redux 状态下,state.user.user
是未定义的,这就是为什么你不能解构 firstName
、lastName
、email
值。
如果在您的商店中 state.user.user
至少是一个已定义的空对象 ({}
),则应解决 null 错误的访问。
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) => {
...
}
我已经实现了我的应用程序的身份验证部分(使用 MERN 堆栈构建)。登录操作验证登录数据,然后加载用户数据,然后将路由推送到 /dashboard
。在仪表板页面上,我有一个简单的 Welcome to the dashboard, {email}!
但是我收到一条错误消息,告诉我它不能 return 空数据。我还在导航栏中有用户的名字和姓氏以及他们的电子邮件,这也会产生 returning 空数据的错误。我有一个 useEffect 可以在我的 App.js
中加载用户数据,但我仍然收到空错误。
有没有办法在渲染之前加载数据?
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'));
});
};
views/app-views/dashboard
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;
看来您可以通过更改 Redux 存储初始状态来解决此问题。
以您的 Dashboard 组件为例:
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': ''}}});
所以错误告诉你,在你的 redux 状态下,state.user.user
是未定义的,这就是为什么你不能解构 firstName
、lastName
、email
值。
如果在您的商店中 state.user.user
至少是一个已定义的空对象 ({}
),则应解决 null 错误的访问。
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) => {
...
}