反应挂钩:useState/context;无法读取 undefined/How 的 属性 'avatar' 来更新嵌套对象
React hooks: useState/context; Cannot read property 'avatar' of undefined/How to update a nested object
我已经从上下文文件中传递了一个状态变量和函数:
用户上下文:
import React, { useState } from 'react';
const UserContext = React.createContext();
function UserProvider({ children }) {
var [userImages, setUserImages] = useState({
avatar: '/static/uploads/profile-avatars/placeholder.jpg'
});
return (
<UserContext.Provider
value={{
userImages,
setUserImages
}}
>
{children}
</UserContext.Provider>
);
}
export default UserContext;
export { UserProvider };
此时 UserImages
只是一个具有一个属性的对象,即 avatar
这是我的应用程序,由提供程序包装(请忽略 redux 实现,我只是想尝试上下文)
import React from 'react';
import { Provider } from 'react-redux';
import { UserProvider } from './UserContext';
import App from 'next/app';
import withRedux from 'next-redux-wrapper';
import { PersistGate } from 'redux-persist/integration/react';
import reduxStore from '../store/index';
import withReactRouter from '../with-react-router/with-react-router';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
const pageProps = Component.getInitialProps
? await Component.getInitialProps(ctx)
: {};
return { pageProps };
}
render() {
const { Component, pageProps, store } = this.props;
return (
<UserProvider>
<Provider store={store}>
<PersistGate persistor={store.__PERSISTOR} loading={null}>
<Component {...pageProps} />
</PersistGate>
</Provider>
</UserProvider>
);
}
}
我正在尝试使用此
之后的 setState 函数更新一些上下文
但是我还是得到了TypeError: Cannot read property 'avatar' of undefined
这是状态对象的形状:
userData:
setUserImages: ƒ ()
userImages:
avatar: "/static/uploads/profile-avatars/placeholder.jpg"
或
userData : {
setUserImages : SetUserImages function,
userImages : {
avatar : "/static/uploads/profile-avatars/placeholder.jpg"
}
}
我的组件:
function ImageUploader({ userData }) {
var { avatar } = userData.userImages;
var setUserAvatar = userData.setUserImages;
function avatarUpdater(avatarPath) {
setUserAvatar({ userData: { ...userData.userImages.avatar, avatarPath } });
}
}
有人知道为什么会这样吗?
UserProvider
是你的app的root,所以你可以直接在ImageUploader
中获取{userImages, setUserImages}
function ImageUploader() {
const {userImages, setUserImages} = useContext(UserContext)
const { avatar } = userImages;
function avatarUpdater(avatarPath) {
setUserImages({ avatar: avatarPath });
}
}
通常最好不要从您的上下文中公开 setState
。你想将它包装在一个显式方法中以更新状态,然后将该方法添加到你的提供者中。类似于:
const userContext = {
avatar: userImages,
updateAvatarUrl: (url) => {
setUserImages(prevState => ({...prevState, avatar: url}))
}
}
return <UserContext.Provider value={userContext}>{children}</UserContext.Provider>
尝试为您的 UserContext 添加一个挂钩,您可以在组件中使用它。
在UserContext
中添加
export const useUserContext = () => useContext(UserContext)
然后在你的组件中:
import { useUserContext } from '<UserContext import>'
...
function avatarUpdater(avatarPath) {
userCtx.updateAvatarUrl(avatarPath)
}
我认为 Context 的最简洁结构。允许更精确地控制上下文状态。
我已经从上下文文件中传递了一个状态变量和函数:
用户上下文:
import React, { useState } from 'react';
const UserContext = React.createContext();
function UserProvider({ children }) {
var [userImages, setUserImages] = useState({
avatar: '/static/uploads/profile-avatars/placeholder.jpg'
});
return (
<UserContext.Provider
value={{
userImages,
setUserImages
}}
>
{children}
</UserContext.Provider>
);
}
export default UserContext;
export { UserProvider };
此时 UserImages
只是一个具有一个属性的对象,即 avatar
这是我的应用程序,由提供程序包装(请忽略 redux 实现,我只是想尝试上下文)
import React from 'react';
import { Provider } from 'react-redux';
import { UserProvider } from './UserContext';
import App from 'next/app';
import withRedux from 'next-redux-wrapper';
import { PersistGate } from 'redux-persist/integration/react';
import reduxStore from '../store/index';
import withReactRouter from '../with-react-router/with-react-router';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
const pageProps = Component.getInitialProps
? await Component.getInitialProps(ctx)
: {};
return { pageProps };
}
render() {
const { Component, pageProps, store } = this.props;
return (
<UserProvider>
<Provider store={store}>
<PersistGate persistor={store.__PERSISTOR} loading={null}>
<Component {...pageProps} />
</PersistGate>
</Provider>
</UserProvider>
);
}
}
我正在尝试使用此
但是我还是得到了TypeError: Cannot read property 'avatar' of undefined
这是状态对象的形状:
userData:
setUserImages: ƒ ()
userImages:
avatar: "/static/uploads/profile-avatars/placeholder.jpg"
或
userData : {
setUserImages : SetUserImages function,
userImages : {
avatar : "/static/uploads/profile-avatars/placeholder.jpg"
}
}
我的组件:
function ImageUploader({ userData }) {
var { avatar } = userData.userImages;
var setUserAvatar = userData.setUserImages;
function avatarUpdater(avatarPath) {
setUserAvatar({ userData: { ...userData.userImages.avatar, avatarPath } });
}
}
有人知道为什么会这样吗?
UserProvider
是你的app的root,所以你可以直接在ImageUploader
{userImages, setUserImages}
function ImageUploader() {
const {userImages, setUserImages} = useContext(UserContext)
const { avatar } = userImages;
function avatarUpdater(avatarPath) {
setUserImages({ avatar: avatarPath });
}
}
通常最好不要从您的上下文中公开 setState
。你想将它包装在一个显式方法中以更新状态,然后将该方法添加到你的提供者中。类似于:
const userContext = {
avatar: userImages,
updateAvatarUrl: (url) => {
setUserImages(prevState => ({...prevState, avatar: url}))
}
}
return <UserContext.Provider value={userContext}>{children}</UserContext.Provider>
尝试为您的 UserContext 添加一个挂钩,您可以在组件中使用它。
在UserContext
中添加
export const useUserContext = () => useContext(UserContext)
然后在你的组件中:
import { useUserContext } from '<UserContext import>'
...
function avatarUpdater(avatarPath) {
userCtx.updateAvatarUrl(avatarPath)
}
我认为 Context 的最简洁结构。允许更精确地控制上下文状态。