【问题标题】:How can I merge ...object and return value of function call in setState(react-hook)?如何在 setState(react-hook) 中合并 ...object 和函数调用的返回值?
【发布时间】:2019-06-27 16:31:08
【问题描述】:

无法合并...状态和函数返回的结果。

我正在尝试将类组件更改为功能组件。

所以我更新了 react 并使用了钩子。

首先我想改变类的状态,setState 来挂钩那些。

但是钩子的 setState 替换 oject 不像类的 setState 那样合并。

下面是原代码

import React from 'react'
import produce from 'immer'
import {
  getUserFromCookie,
  login,
  logout,
  profile,
  updateProfile
} from '../api'

const userInfo = getUserFromCookie()
const UserContext = React.createContext({
  ...userInfo
})

export const withUserContext = WrappedComponent => {
  return class ProviderComponent extends React.Component {
    constructor(props) {
      super(props)
      this.state = {
        ...userInfo,
        consentNeeded: false,
        updateConsent: async ({ pi, news, seen }) => {
          await updateProfile({ pi, news, seen })
          this.setState({
            consentNeeded: false
          })
        },
        profile: async () => {
          const userProfile = await profile()
          if (userProfile.seen_consent_modal === false) {
            this.setState({
              consentNeeded: true
            })
          }
        },
        login: async ({ userId, password }) => {
          const user = await login({ userId, password })
          this.setState(
            produce(draft => {
              return user
            })
          )
        },
        logout: async () => {
          await logout()
        }
      }
    }

    render() {
      return (
        <UserContext.Provider value={this.state}>
          <WrappedComponent {...this.props} />
        </UserContext.Provider>
      )
    }
  }
}

export default UserContext

这是我工作的功能组件。

import React, { useState } from 'react'
import produce from 'immer'
import {
  getUserFromCookie,
  login,
  logout,
  profile,
  updateProfile
} from '../api'

const userInfo = getUserFromCookie()
const UserContext = React.createContext({
  ...userInfo
})

export const withUserContext = WrappedComponent => {
  return function provideComponent() {

    const [state, setState] = useState({
      ...userInfo,
      consentNeeded: false,
      updateConsent: async ({ pi, news, seen }) => {
        console.error('updateConsent!!')
        await updateProfile({ pi, news, seen })
        setState({
          consentNeeded: false
        })
      },
      profile: async () => {
        console.error('profile!!')
        const userProfile = await profile()
        if (userProfile.seen_consent_modal === false) {
          setState({
            consentNeeded: true
          })
        }
      },
      login: async ({ userId, password }) => {
        const user = await login({ userId, password })

        setState(
          produce(() => user)
        )
      },
      logout: async () => {
        await logout()
      }
    })

    return (
      <UserContext.Provider value={state}>
        <WrappedComponent {...props} />
      </UserContext.Provider>
    )
  }
}

export default UserContext

下划线警告..我认为它的语法不正确

【问题讨论】:

  • 你为什么把async函数放在初始state的值里面?你希望他们怎么称呼?什么时候?更好地附加基于源类的组件(但不是所有内容 - 只需单个 state 的键和加载就足够的函数)
  • 现在我可以说看起来像滥用useState - 它的参数是一些状态数据的初始值,就像你可以在构造函数中为基于类的组件初始化它一样:this.state = { .... }; 基于道具。这里也是一样。所以通常你不想在那里有函数。
  • 我建议你,对于复杂的组件使用类组件!功能组件有不同的用例......在这里你应该写 {...state, *****} 而不是 {...userInfo, *****}

标签: reactjs react-hooks


【解决方案1】:

编辑:

我意识到了问题所在。我做了一个codesandbox,一切正常(除了你没有提供的功能)。

1。 HOCs 应该用于 Contex.Consumer 而不是 Context.Provider

在您的代码中,您正在为Context.Provider 创建一个HOC,但正确的方法应该是为Contex.Consumer

要使用上下文,您需要

<Contex.Provider>
    ...
    <AnyThingYouWant>
        <Context.Consumer>
        </Context.Consumer>
    </AnyThingYouWant>
</Contex.Provider>

如果您想要 Contex.ProviderHOC,您只需使用 children 并将其包裹在您的组件周围

例如

const UserContext = React.createContext('my context')

const UserProvider = (props) => {

    const value = useState('someState')

    return (
        <UserContext.Provider value={value}>
            {children}
        </UserContext.Provider>
    )

}

2。如果您使用的是功能组件,则不再需要HOC

React Hooks 引入 useContext

现在您唯一需要渲染Context.Provider 并像const {...contextValue} = useContext(MyContext) 一样使用它。

例如

const { updateConsent, profile, login, logout, ...otherStuff } = useContex(UserContext)

3.Inside Context.Consumer 你需要传递一个函数来渲染WrappedComponent

在为Context.Consumer 制作HOC 时,您需要有一个函数来呈现WrappedComponent 并从消费者那里接收props

例如

const withUserContext = WrappedComponent => {
  return function UserContextHoc(props) {
    return (
      <UserContext.Consumer>
        // function that render the `WrappedComponent`
        {consumerProps => <WrappedComponent {...props} {...consumerProps} />}
      </UserContext.Consumer>
    );
  };
};

如果你这样做,那就错了

<UserContext.Consumer>
    // THIS IS WRONG AND WILL THROW AN ERROR
    <WrappedComponent {...props} />
</UserContext.Consumer>

如果您查看codesandbox,您会发现它没有给出任何错误,而且在MyComponent 内的console 中,它显示了来自UserContext 的所有内容。

希望现在一切都更清楚了。


旧:

您的函数应该在useState 初始值之外才能调用setState

// state has multiple key value
 const [state, setState] = useState({
      ...userInfo,
      consentNeeded: false,      
    })
const updateConsent = async ({ pi, news, seen }) => {
        await updateProfile({ pi, news, seen })
        setState({
          consentNeeded: false
        })
      }

const profile = async () => {
        const userProfile = await profile()
        if (userProfile.seen_consent_modal === false) {

          // setState(prevState => {
          //   return {...prevState, {consentNeeded: true}};
          // });
          setState({
            consentNeeded: true
          })
        }
      }

const login = async ({ userId, password }) => {
        const user = await login({ userId, password })
        // code below change it as produce's result. 
        // not merging of exist states

        // setState(
        //   produce(() => {
        //     return user
        //   })
        // )

       // what I've tried.. but warning underline..
        setState(prevState => {...prevState, produce(() => user)})
}

const logout = async () => {
    await logout()
}

    return (
      <UserContext.Provider value={{
        ...state,
        updateConsent,
        profile,
        login,
        logout,
      }>
        <WrappedComponent {...props} />
      </UserContext.Provider>
    )

【讨论】:

  • 第 90 行:解析错误:意外令牌 javascript 88 | const user = await login({ userId, password }) 89 | &gt; 90 | setState(prevState =&gt; {...prevState, produce(()=&gt;user)}) | ^ 91 | } 92 | const logout = async () =&gt; { 93 | await logout() 它不起作用...
  • @sunheekyung 你能在你的问题中发布完整的代码吗?您的组件的完整代码。如果您收到意外的令牌,这只是一些语法问题,很容易修复
  • 我发布了原始代码,我正在处理但效果不佳
  • @sunheekyung 我只是用完整的工作示例和更好的解释来编辑我的答案,希望它现在有所帮助!
猜你喜欢
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 2021-06-16
  • 1970-01-01
  • 1970-01-01
  • 2022-12-03
  • 2020-10-28
  • 1970-01-01
相关资源
最近更新 更多