反应挂钩: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 的最简洁结构。允许更精确地控制上下文状态。