反应钩子:useState/context;无法读取未定义的属性“头像”/如何更新嵌套对象

Posted

技术标签:

【中文标题】反应钩子:useState/context;无法读取未定义的属性“头像”/如何更新嵌套对象【英文标题】:React hooks: useState/context; Cannot read property 'avatar' of undefined/How to update a nested object 【发布时间】: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 【参考方案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 结构最简洁。允许更精确地控制上下文状态。

【讨论】:

以上是关于反应钩子:useState/context;无法读取未定义的属性“头像”/如何更新嵌套对象的主要内容,如果未能解决你的问题,请参考以下文章

反应:带有自定义钩子的滑块无法正常工作

反应:无法使用 useContext 钩子在 app.js 中设置上下文状态

反应钩子形式 - 类型错误:无法读取 L 处未定义的属性“拆分”(get.ts:6)

反应钩子第一次没有设置状态

在 HoC 中使用反应钩子时的警告

使用 null GraphQL 数据反应原生钩子