-1

I am having a sample react app with 2 components Component1 & Component2 as below. i am using useContext hook to update the context value in Component2 and reading the updated context value in Component1. This is working as expected and i am able to read the updated value from context in Component1

Issue: If i am trying to read the context value after updating it in Component2 itself, then its printing the prev values ('initial text') and NOT the latest updated value ('updated text').

Goal: With this sample app, i am trying to use react context to set and get values within same component. I know to get the updated value we can do setState within the component, but i do not want to do that as i am already setting the value in context , so why not get from same context within the component (Component2 in this case)

AppContext.tsx

const AppContext = createContext('create context text'); export default AppContext; 

Root.tsx

export const Root = (props) => { const [context1, setContext1] = useState('initial text'); return ( <AppContext.Provider value={{context1, setContext1}}> {props.children} </AppContext.Provider> ) } 

App.tsx

const App = () => { return ( <Root> <Component1></Component1> <Component2></Component2> </Root> ) } export default App 

Component1.tsx

const Component1 = () => { const {context1, setContext1} = useContext(AppContext); console.log('context ', context1); // **This prints 'updated text' as expected** useEffect(() => { console.log('Comp1 useEffect'); },[]); const buttonHandler2 = () => { console.log('appname context updated ' + context1); } return ( <> <div>comp1 Name: {context1} </div> <button onClick={buttonHandler2}>Check name</button> </> ); } export default Component1; 

Component2.tsx

const Component2 = () => { const {context1, setContext1} = useContext(AppContext); useEffect(() => { console.log('Comp2 useEffect'); },[]); const buttonHandler = () => { setContext1((prev) => { return 'updated text'; }); console.log('context ', context1); //This prints 'initial text', but since we are doing //setContext above, it should print 'updated text' } return ( <> <button onClick={buttonHandler}>Update name</button> </> ); } export default Component2; 
5
  • Your context contains state data, setting the state in React is always an asynchronous action, the value will not be immediately available. See: Why does calling react setState method not mutate the state immediately?
    – DBS
    CommentedJun 6, 2024 at 9:01
  • Thanks for the reply. But i think, if we do setState using the prevState value, then it updates immidiately. ex: setState((prevState) => return {...prevState, 'updated value'});CommentedJun 6, 2024 at 9:09
  • 1
    @RiteshKaushik it does not. State updates are async
    – Petros
    CommentedJun 6, 2024 at 9:17
  • To achieve printing or executing some logic after the context1 changes, then u can use useEffect(()=>{ //do something }, [context1])
    – Petros
    CommentedJun 6, 2024 at 9:19
  • 1
    @RiteshKaushik Passing in the previous value ensures you don't use an outdated value when constructing your new state, but has no impact on when that new state becomes available.
    – DBS
    CommentedJun 6, 2024 at 9:42

1 Answer 1

1

//This prints 'initial text', but since we are doing setContext above, it should print 'updated text'

This is not correct. This is not a typical setter like in Java, where the value is updated immediately. This is more like ordering a state update, which will come to life only on the next render - you can think of it as asynchronous.

This entry in React Docs explains it.

You don't specify what exactly are you trying to achieve in the grander scheme of things, so I can't tell you what you can do instead.

EDIT: After you explained more about what you need, more information comes below:

You are using and updater function to set new state (docs on updater function). They are used to create new state from previous state and in the docs they state:

If you do multiple updates within the same event, updaters can be helpful. They’re also helpful if accessing the state variable itself is inconvenient.

Neither of these seem to be your case so I guess you've heard something like "the updater function always get an up-to-date state" and you wanted this up-to-date state to be accessible in your buttonHandler. Unless you do things mentioned in the quote above, you don't have to worry about that. You can totally use the state in handlers, effects etc. and it will be up-to-date, since handlers are recreated from scratch on every render (unless optimized, but don't dig into that too soon) and effects are specifically called when something in their dependency array changes.

Try this out:

import React from 'react'; function Component2() { const { context1, setContext1 } = React.useContext(AppContext); React.useEffect(() => { //this is going to be called every time the context changes state console.log('Comp2 useEffect, state of context1:', context1); }, [context1]); //notice the context1 in the deps array function buttonHandler1() { console.log('buttonHandler1, state of the context before change:', context1); setContext1(prevName => { const modifiedName = prevName + ' a modification to the state'; console.log('buttonHandler1, new name:', modifiedName); return modifiedName; }); } function buttonHandler2() { console.log('buttonHandler2, state of the context before change:', context1); const modifiedName = context1 + ' a modification to the state'; console.log('buttonHandler2, new name:', modifiedName); setContext1(modifiedName); } function buttonHandler3() { console.log('buttonHandler3, state of the context before change:', context1); setContext1('completely new name'); } function resetState() { setContext1('initial text'); } return ( <> <p>current state of the context: </p> <p>{context1}</p> <button onClick={buttonHandler1}>Update name, method1</button> <button onClick={buttonHandler2}>Update name, method2</button> <button onClick={buttonHandler3}>set completely new name</button> <button onClick={resetState}>reset</button> </> ); } export default Component2; 
2
  • Thanks for the reply. i have updated the question with the Goal i am trying to achieve with this sample appCommentedJun 6, 2024 at 11:13
  • I've updated the answer, check it outCommentedJun 6, 2024 at 15:33

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.