5

I have a component that creates three radio buttons. Cicking one should update a context store I have elsewhere.

My state looks like this:

const styles = {
    font: {
        size: {
            value: '22',
            unit: 'px'
        },
        weight: 'bold',
        color: '#663300',
        family: 'arial',
        align: 'center'
    }
};

I store my state like this:

const myContext = useEmailContext();
const { ...styling } = styles;
const [style, setStyle] = useState({ styling });

And then my component fires the functions onChange:

return (
    <RadioButtonGroup
        onChange={(event) => {
            setIsChecked({ checked: event.target.value });
            setStyle({ ...styling,  font: { ...styling.font, align: event.target.value } });
            console.log(style);
            myContext.setStyles(style);
        }}
    />

When I click a button the function fires, but the console.log shows the previous state, not the newly updated one. Similarly, my context also get updated one step behind.

What's going on here?

codemon
  • 1,456
  • 1
  • 14
  • 26

2 Answers2

0

state update is asynchronous with useState hooks updater. You can read more about it on this post:

useState set method not reflecting change immediately

However you can solve the context value update like

return (
    <RadioButtonGroup
        onChange={(event) => {
            setIsChecked({ checked: event.target.value });
            const newStyle = { ...styling,  font: { ...styling.font, align: event.target.value } }
            setStyle(newStyle);
            myContext.setStyles(newStyle);
        }}
    />
)

or you can update the context value with useEffect hook like

useEffect(() => {
     myContext.setStyles(styling);
}, [styling]);

return (
    <RadioButtonGroup
        onChange={(event) => {
            setIsChecked({ checked: event.target.value });
            setStyle({ ...styling,  font: { ...styling.font, align: event.target.value } });
        }}
    />
)
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • maybe the correct place to handle it is in useEffect() ? So wherever and whenever styles changes it would be propagated to the context without an explicit set to the context in every method. – Mosè Raguzzini Jun 28 '19 at 10:45
  • @MosèRaguzzini That is one way to do it, but since the same styles are to be passed on to the context and state, I don't think we need useEffect. The above solution will work correctly :-) – Shubham Khatri Jun 28 '19 at 10:53
  • Hi mate, I understand that this "just works" but I've just followed the link inside your answer and it states the same thing. Although your solution works, this is not the final or cleanest solution. – Mosè Raguzzini Jun 28 '19 at 10:59
0

Answer from Shubham Khatri should work as expected, but the cleanest solution is to use useEffect() hook:

useEffect(() => {
    // this is the place to update your context, and it will work every time style is updated, everytime, everywhere.
}, [style]);

This will prevent you from updating your context by hand whenever a change occurs.

Mosè Raguzzini
  • 15,399
  • 1
  • 31
  • 43