Как я могу объединить ... объект и вернуть значение вызова функции в setState (реагировать на это)? - PullRequest
1 голос
/ 27 июня 2019

Невозможно объединить ... состояние и результат возврата функции.

Я пытаюсь изменить компонент класса на компонент функции.

поэтому я обновил реакцию и использовал крючок.

Прежде всего, я хочу изменить состояние класса, 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

Подчеркните предупреждение .. Я думаю, что это не правильный синтаксис

1 Ответ

0 голосов
/ 27 июня 2019

Редактировать:

Я понял, в чем проблема.Я сделал коды и коробку , где все работает (кроме функций, которые вы не предоставили).

1.HOC s следует использовать для Contex.Consumer Не Context.Provider

В вашем коде вы делаете HOC для Context.Provider, но правильный путь должен быть для Contex.Consumer.

Для работы с контекстом вам понадобится

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

Если вы хотите HOC для Contex.Provider, вам нужно всего лишь использовать 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. Внутри Context.Consumer вам нужно передать функцию, которая отображает WrappedComponent

При создании HOC для Context.Consumer необходимо иметь функцию, которая визуализирует 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 , вы увидите, что оно не дает ошибок, а также во console внутри MyComponent, он показывает все, что из 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>
    )
...