【问题标题】:React hooks: useState/context; Cannot read property 'avatar' of undefined/How to update a nested object反应钩子:useState/context;无法读取未定义的属性“头像”/如何更新嵌套对象
【发布时间】:2020-09-30 00:49:26
【问题描述】:

我已经从上下文文件中传递了一个状态变量和函数:

用户上下文:

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

这是我的应用程序正在被 Provider 包装(请忽略 redux 的实现,我只是想试试 Context)

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>
    );
  }
}

我正在尝试使用 post 之后的 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 } });
    }
  }

有人知道为什么会这样吗?

【问题讨论】:

  • 您可能需要先确认userDatauserData.userImages,然后才能从中获取avatar userData 来自哪里?这个问题与 react-context 有什么关系?
  • @TonyNguyen 你是对的,也许我应该更新我的问题,我添加了一些上下文......
  • 你在哪里使用ImageUploader

标签: reactjs react-hooks react-context use-state


【解决方案1】:

UserProvider是你app的根,所以你可以直接在ImageUploader中获取{userImages, setUserImages}

function ImageUploader() {
  const {userImages, setUserImages} = useContext(UserContext)
  const { avatar } = userImages;

  function avatarUpdater(avatarPath) {
     setUserImages({ avatar: avatarPath });
  }
}

【讨论】:

    【解决方案2】:

    通常最好的做法是不要从您的上下文中公开setState。您想将其包装在一个显式方法中以更新状态,然后将该方法添加到您的 Provider 中。比如:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-14
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2019-10-08
      • 1970-01-01
      • 1970-01-01
      • 2021-03-14
      相关资源
      最近更新 更多