使用挂钩更新上下文状态值

时间:2019-03-04 21:47:12

标签: reactjs

我正在尝试遵循this guide的“如何在上下文中使用基本的React钩子”这一知识,它非常擅长为上下文组件提供基本结构,但是没有涉及如何在没有上下文的情况下更新片段默认值返回。

我正在尝试实现类似这样的东西

import React, { Component, useContext, useState } from 'react';

export const ProfileContext = React.createContext<ContextState | null>(null);

interface ContextState {
  changeInformation: Function
  team: string
  company: string
}

export const ProfileProvider = (props) => {
  const userInformation = {
    company: 'Progress',
    companyImage: 'https://svgshare.com/i/9ir.svg',
    url: 'https://www.telerik.com/kendo-react-ui/',
    userImage: 'https://i.imgur.com/Y1XRKLf.png',
    userName: 'Kendoken',
    fullName: 'Kendoken No Michi',
    team: 'KendoReact',
    // This sets all the initial values but changes the team.
    // I want to make a function that changes any property by name to the new value
    changeInformation: (property: string, value: any) => {
      let newInfo = {...userInfo}
      newInfo[property] = value
      setUserInfo(newInfo);
    }
  }

  // create `userInfo` with update method called `setUserInfo`
  // set default to `userInformation`
  const [userInfo, setUserInfo] = useState(userInformation);
  return (
    <ProfileContext.Provider value={userInfo}>
      {props.children}
    </ProfileContext.Provider>
  )
}

由于某些原因,在多次更新后,默认值将返回而不是更新后的状态。我的子组件看起来像这样:

import React, { useContext } from 'react';
import { ProfileContext } from "../data"

export const ChangeTeam = () => {
    const context = useContext(ProfileContext);
    return (
      <>
        <button className="profile-button"
          onClick={() => context.changeInformation('team', 'Vue')}>Vue</button>
        <button className="profile-button"
          onClick={() => context.changeInformation('company', 'React')}>React</button>
        <p>Team: {context.team}</p>
        <p>Company: {context.company}</p>
      </>
    )
  }

我知道我做错了一些事情,让它调用默认值,但是我不确定修复该问题的结构。

如果您有任何见解,请告诉我。

更新-(我知道这些值是不同的),我已经满足了我的需要,但是我觉得应该有一种更清洁的方式来管理它:

import React, { Component, useContext, useState, useEffect } from 'react';

export const ProfileContext = React.createContext<ContextState | null>(null);

interface ContextState {
    setCompany: Function
    setName: Function
    name: string
    company: string
}

export const ProfileProvider = (props: {children: HTMLElement}) => {
  const [company, setCompany] = useState('Progress');
  const [name, setName] = useState('Bill');

  return (
    <ProfileContext.Provider value={{company, setCompany, name, setName}}>
      {props.children}
    </ProfileContext.Provider>
  )
}

我希望能够动态地将未知项目添加到状态,这就是为什么第一种方法似乎可以更好地完成技巧的原因,但是我不确定。

干杯

2 个答案:

答案 0 :(得分:0)

我做到了,它似乎正在起作用:

import React, { Component, useContext, useState, useEffect } from 'react';

export const ProfileContext = React.createContext<ContextState | null>(null);

interface ContextState {
  changeInformation: Function
  team: string
  company: string
  address: string
}

export const ProfileProvider = (props: {children: HTMLElement}) => {
  const userInformation = {
    company: 'Progress',
    companyImage: 'https://svgshare.com/i/9ir.svg',
    url: 'https://www.telerik.com/kendo-react-ui/',
    userImage: 'https://i.imgur.com/Y1XRKLf.png',
    userName: 'Kendoken',
    fullName: 'Kendoken No Michi',
    team: 'KendoReact',
    // This sets all the initial values but changes the team.
    // I want to make a function that changes any property by name to the new value
    changeInformation: (property: string, value: any) => {
      setUserInfo(prevInfo => ({
        ...prevInfo,
        [property]: value
      }) );
    }
  }

  // create `userInfo` with update method called `setUserInfo`
  // set default to `userInformation`
  const [userInfo, setUserInfo] = useState(userInformation)

  return (
    <ProfileContext.Provider value={userInfo}>
      {props.children}
    </ProfileContext.Provider>
  )
}

这似乎与演示完全一样,但是由于某种原因,我无法使演示正常工作。我认为是因为我将其设置为prevInfo。

答案 1 :(得分:0)

看来您已经解决了问题,但是我可以建议您稍微修改一下吗? 在理想情况下(对我而言),您应该保持数据纯净,而且我认为也没有理由在其中具有更新功能。

export const ProfileProvider = (props: { children: HTMLElement }) => {
  const userInformation = {
    company: 'Progress',
    companyImage: 'https://svgshare.com/i/9ir.svg',
  };

  const [userInfo, setUserInfo] = useState(userInformation)

  const changeInfo = (property: string, value: any) =>
    setUserInfo(prevInfo => ({ ...prevInfo, [property]: value }));

  return (
    <ProfileContext.Provider value={{ userInfo, changeInfo }}>
      {props.children}
    </ProfileContext.Provider>
  )
}

export const ChangeTeam = () => {
  const { userInfo, changeInfo } = useContext(ProfileContext);
  return (
    <>
      <button className="profile-button"
        onClick={() => changeInfo('team', 'Vue')}>Vue</button>
      <p>Team: {userInfo.team}</p>
    </>
  )
}