score:501
using hooks
hooks were introduced in 16.8.0 so the following code requires a minimum version of 16.8.0 (scroll down for the class components example). codesandbox demo
1. setting parent state for dynamic context
firstly, in order to have a dynamic context which can be passed to the consumers, i'll use the parent's state. this ensures that i've a single source of truth going forth. for example, my parent app will look like this:
const app = () => {
const [language, setlanguage] = usestate("en");
const value = { language, setlanguage };
return (
...
);
};
the language
is stored in the state. we will pass both language
and the setter function setlanguage
via context later.
2. creating a context
next, i created a language context like this:
// set the defaults
const languagecontext = react.createcontext({
language: "en",
setlanguage: () => {}
});
here i'm setting the defaults for language
('en') and a setlanguage
function which will be sent by the context provider to the consumer(s). these are only defaults and i'll provide their values when using the provider component in the parent app
.
note: the languagecontext
remains same whether you use hooks or class based components.
3. creating a context consumer
in order to have the language switcher set the language, it should have the access to the language setter function via context. it can look something like this:
const languageswitcher = () => {
const { language, setlanguage } = usecontext(languagecontext);
return (
<button onclick={() => setlanguage("jp")}>
switch language (current: {language})
</button>
);
};
here i'm just setting the language to 'jp' but you may have your own logic to set languages for this.
4. wrapping the consumer in a provider
now i'll render my language switcher component in a languagecontext.provider
and pass in the values which have to be sent via context to any level deeper. here's how my parent app
look like:
const app = () => {
const [language, setlanguage] = usestate("en");
const value = { language, setlanguage };
return (
<languagecontext.provider value={value}>
<h2>current language: {language}</h2>
<p>click button to change to jp</p>
<div>
{/* can be nested */}
<languageswitcher />
</div>
</languagecontext.provider>
);
};
now, whenever the language switcher is clicked it updates the context dynamically.
using class components
the latest context api was introduced in react 16.3 which provides a great way of having a dynamic context. the following code requires a minimum version of 16.3.0. codesandbox demo
1. setting parent state for dynamic context
firstly, in order to have a dynamic context which can be passed to the consumers, i'll use the parent's state. this ensures that i've a single source of truth going forth. for example, my parent app will look like this:
class app extends component {
setlanguage = language => {
this.setstate({ language });
};
state = {
language: "en",
setlanguage: this.setlanguage
};
...
}
the language
is stored in the state along with a language setter method, which you may keep outside the state tree.
2. creating a context
next, i created a language context like this:
// set the defaults
const languagecontext = react.createcontext({
language: "en",
setlanguage: () => {}
});
here i'm setting the defaults for language
('en') and a setlanguage
function which will be sent by the context provider to the consumer(s). these are only defaults and i'll provide their values when using the provider component in the parent app
.
3. creating a context consumer
in order to have the language switcher set the language, it should have the access to the language setter function via context. it can look something like this:
class languageswitcher extends component {
render() {
return (
<languagecontext.consumer>
{({ language, setlanguage }) => (
<button onclick={() => setlanguage("jp")}>
switch language (current: {language})
</button>
)}
</languagecontext.consumer>
);
}
}
here i'm just setting the language to 'jp' but you may have your own logic to set languages for this.
4. wrapping the consumer in a provider
now i'll render my language switcher component in a languagecontext.provider
and pass in the values which have to be sent via context to any level deeper. here's how my parent app
look like:
class app extends component {
setlanguage = language => {
this.setstate({ language });
};
state = {
language: "en",
setlanguage: this.setlanguage
};
render() {
return (
<languagecontext.provider value={this.state}>
<h2>current language: {this.state.language}</h2>
<p>click button to change to jp</p>
<div>
{/* can be nested */}
<languageswitcher />
</div>
</languagecontext.provider>
);
}
}
now, whenever the language switcher is clicked it updates the context dynamically.
score:0
just wanted to add to divyanshu maithani's answer that it's generally safer to use usememo
when wrapping the consumer in a provider.
const app = () => {
const [language, setlanguage] = usestate("en");
const value = usememo(
() => ({ language, setlanguage }),
[language, setlanguage ],
);
return (
<languagecontext.provider value={value}>
<h2>current language: {language}</h2>
<p>click button to change to jp</p>
<div>
{/* can be nested */}
<languageswitcher />
</div>
</languagecontext.provider>
);
};
from react/jsx-no-constructed-context-values rule :
react context, and all its child nodes and consumers are rerendered whenever the value prop changes. because each javascript object carries its own identity, things like object expressions ({foo: 'bar'}) or function expressions get a new identity on every run through the component. this makes the context think it has gotten a new object and can cause needless rerenders and unintended consequences.
this can be a pretty large performance hit because not only will it cause the context providers and consumers to rerender with all the elements in its subtree, the processing for the tree scan react does to render the provider and find consumers is also wasted.
score:4
one quite simple solution is to set state on your context by including a setstate method in your provider like so:
return (
<context.provider value={{
state: this.state,
updatelanguage: (returnval) => {
this.setstate({
language: returnval
})
}
}}>
{this.props.children}
</context.provider>
)
and in your consumer, call updatelanguage like so:
// button that sets language config
<context.consumer>
{(context) =>
<button onclick={context.updatelanguage({language})}>
set to {language} // if you have a dynamic val for language
</button>
<context.consumer>
score:8
i personally like this pattern:
file: context.jsx
import react from 'react';
// the context
const templatecontext = react.createcontext({});
// template provider
const templateprovider = ({children}) => {
const [myvalue, setmyvalue] = react.usestate(0);
// context values passed to consumer
const value = {
myvalue, // <------ expose value to consumer
setmyvalue // <------ expose setter to consumer
};
return (
<templatecontext.provider value={value}>
{children}
</templatecontext.provider>
)
}
// template consumer
const templateconsumer = ({children}) => {
return (
<templatecontext.consumer>
{(context) => {
if (context === undefined) {
throw new error('templateconsumer must be used within templateprovider');
}
return children(context)
}}
</templatecontext.consumer>
)
}
// usetemplate hook
const usetemplate = () => {
const context = react.usecontext(templatecontext);
if(context === undefined)
throw new error('usetemplate must be used within templateprovider');
return context;
}
export {
templateprovider,
templateconsumer,
usetemplate
}
then you can create a functional component, if it is a child in the tree of the provider:
file: component.jsx
import react from 'react';
import {usetemplate} from 'context.jsx';
const mycomponent = () => {
// get the value and setter from the consumer hook
const {myvalue, setmyvalue} = usetemplate();
// demonstrate incrementing the value
react.useeffect(() => {
// increment, set in context
const increment = () => setmyvalue(prev => prev + 1);
// increment every second
let interval = setinterval(increment, 1000);
// cleanup, kill interval when unmounted
return () => clearinterval(interval);
},[]) // on mount, no dependencies
// render the value as it is pulled from the context
return (
<react.fragment>
value of myvalue is: {myvalue}
</react.fragment>
)
}
score:88
since it is recommended by react to use functional components and hooks so i will implement it with usecontext and usestate hooks. here is how you can update the context from within a child component.
languagecontextmangement.js
import react, { usestate } from 'react'
export const languagecontext = react.createcontext({
language: "en",
setlanguage: () => {}
})
export const languagecontextprovider = (props) => {
const setlanguage = (language) => {
setstate({...state, language: language})
}
const initstate = {
language: "en",
setlanguage: setlanguage
}
const [state, setstate] = usestate(initstate)
return (
<languagecontext.provider value={state}>
{props.children}
</languagecontext.provider>
)
}
app.js
import react, { usecontext } from 'react'
import { languagecontextprovider, languagecontext } from './languagecontextmanagement'
function app() {
const state = usecontext(languagecontext)
return (
<languagecontextprovider>
<button onclick={() => state.setlanguage('pk')}>
current language is: {state.language}
</button>
</languagecontextprovider>
)
}
export default app
Source: stackoverflow.com
Related Query
- How to update React Context from inside a child component?
- How to update parent state from child component in React + send a paramater
- How to update redux state using a react variable passed up to the component from a child
- How to read and update React Context from child with function components?
- How to reset child component from parent using React Context and Hooks
- Update React context from child component
- How to set the state of parent component in react from inside child component
- How do I use react context API to pass data from parent component to child component when using react-router in the parent component in React.js?
- how to stop re-rendering of child component if parent update the context or state in react js?
- How to call a callback from child environment in parent component environment passing by context in react
- How to update data from child component to parent component using context api in react?
- react (class based) : How can I update JSON object in parent component using setState after the object being passed in function from child to parent?
- How to update state in child component with context value from parent (class components)
- How to update state of child component when it get called in map function from parent component React JS
- React Warning: Cannot update a component from inside the function body of a different component
- How to prevent child component from re-rendering when using React hooks and memo?
- How to update the state of a sibling component from another sibling or imported component in REACT
- How do I pass all state variables inside react hooks to my child component
- React: How to add onChange functionality inside of Function component using React Hooks? Need onClick event from a checkbox to influence input state
- Update a react state (array of objects) from a child component
- How to pass input value from child to parent component react
- How to use React Context inside function of Class component
- How to communicate from Child Component to Parent Component with React Router
- Enzyme/Mocha: How to test a react component function by firing an onChange event from a child component
- How is an argument for a callback in React being passed from the child component to the parent component?
- How to change the background color of a parent component from inside a child component in react, gatsby
- How does React Context work by using a function inside of a component
- How can my child component update my parent component in React JS?
- How to pass an Array from Child component to Parent component in react I know how to pass from parent t
- React TS - How to pass props from a parent component to a deeply nested child
More Query from same tag
- React is not defined in working code
- Clear redux state when page transition
- Get height of element when useState is initially set
- React router dynamiclly
- React TypeScript: How to spread in other values of a nested state object
- How to add description in React Storybook -> showInfo
- How to programmatically fill input elements built with React?
- How can I provide variables.scss to each .scss file when bundling with webpack?
- Missing "key" prop for element in iterator react/jsx-key in React
- Calling data from outside of Chartjs code
- React/React-router: Go back to the previous component, bypassing changes in same-component URL parameters
- React.js: props.state is blank(null)
- React Test Renderer Simulating Clicks on Elements
- Shorthand for getting nested values
- Adjacent JSX elements must be wrapped in enclosing tag
- Assign resolve function from Promise to a variable
- Webpack change url in css files
- React: can you use setState with existing state object?
- System limit for number of file watchers reached
- React - how do I unit test an API call in Jest?
- React Render Array in Mapped Return
- Call JS function from another file in React?
- Sending FormData to Spring boot rest API get bad request 400
- Import react-bootstrap in sass
- Babel Webpack Error: You may need an appropriate loader to handle this file type
- Trying to configure throws error
- Rapid onChange causes OnClick not to register
- React - how to extend a component that has child components and keep them?
- Display an alert if the form has errors on submit in react-final-form
- React: recursively render nested elements