Reputation: 1342
I am attempting to follow this guide on "how to use basic react hooks for context" and it is great at giving a basic structure to a context component but doesn't go into how one could update pieces without the default values returning.
I was trying to implement something like this
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>
)
}
For some reason, the default values return rather than the updated state after multiple updates. My child component looks like this:
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>
</>
)
}
I know that I am doing something wrong to have it recall the default values but I am not sure about the structure to fix this.
If you have any insight please let me know.
UPDATE - (I know the values are differnet) I have gotten this to work for my needs but I feel like there should be a cleaner way to manage this:
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>
)
}
I would like to be able to dynamically add unknown items to the state that is why the first approach seems to do the trick slightly better but I am not sure.
Cheers,
Upvotes: 1
Views: 3247
Reputation: 5707
It looks like you've solved your issue, but can I suggest reworking things slightly? Ideally (to me) you'd keep your data pure, and I don't think there's a reason to have the update function in there anyway.
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>
</>
)
}
Upvotes: 1
Reputation: 1342
I did this and it seems to be working:
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>
)
}
It seems exactly like the demo but for some reason, I couldn't get the demo working. I think it is because I set it to the prevInfo instead.
Upvotes: 0