Do you want to request a feature or report a bug?
Feature. useState should return getState.
What is the current behavior?
useState returns an initial state value, and a setter.
Consider:
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import { Generate } from 'genyaj'
const ItemDisplay = () => {
const [items, setItems] = useState([])
const [stopUpdates, setStopUpdates] = useState(false)
const getItemUpdates = async () => {
const { data } = await axios.get(API)
setItems(data)
}
useEffect(() => {
Generate({
task: getItemUpdates,
stop: () => {
let temp
// React doesn't have a getState hook,
// setStopUpdates can read the most current value of stopUpdates
setStopUpdates(s => (temp = s))
return temp
},
interval: 5000
})
}, [])
return (
<div>
<button onClick={() => setStopUpdates(true)}>
{items.map(item => <p>{item.name}</p>)}
</div>
)
}
What is the expected behavior?
const [stopUpdates, setStopUpdates, getStopUpdates] = useState(false)
Generate({
task: getItemUpdates,
// Rather than wrapping setStopUpdates with a temp variable assignment, just cut to the chase.
stop: getStopUpdates,
interval: 5000
})
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
React 16.8.4 | Chrome 73.0.3683.86
Won't setStopUpdates(s => (temp = s)) set stopUpdates to undefined?
Shoud be
setStopUpdates(s => {
temp = s;
return s;
})
Edit: I realised this wouldn't work because setState functions are asynchronous
Instead you'll have to use a ref, i.e
const [stopUpdates, setStopUpdates] = useState(false);
const stopUpdatesRef = useRef(stopUpdates);
useEffect(()=>{
stopUpdatesRef.current = stopUpdates;
});
useEffect(() => {
Generate({
task: getItemUpdates,
stop: () => stopUpdatesRef.current, // <- always up to date
interval: 5000
})
}, [])
you can also write a custom state hook wrapper eh... hook?
const useStateWithGetter = (initialState) => {
const [state, setState] = useState(initialState);
const stateRef = useRef(state);
useEffect(() => {
stateRef.current = state;
});
const getState = useCallback(() => stateRef.current, []);
return [state, setState, getState];
}
// in your component
const [stopUpdates, setStopUpdates, getStopUpdates] = useStateWithGetter(false);
useEffect(() => {
Generate({
task: getItemUpdates,
stop: getStopUpdates, // <- always up to date
interval: 5000
})
}, [])
Won't setStopUpdates(s => (temp = s)) set stopUpdates to undefined?
The (temp = s) expression returns the value assigned to the left-side operand.
you can also write a custom state hook wrapper eh...
This is awesome. I didn't think about using refs this way! thank you very much 馃槃
Although this custom hook addresses the issue I was having, I'm wondering if other people would prefer something like this being a part of the core useState api. If no one else thinks this, then I'd be fine closing this issue.
This is a great idea. It means in useCallbacks and useMemos etc. you won't need to subscribe to the state variable so your references will not change.
Most helpful comment
Won't
setStopUpdates(s => (temp = s))setstopUpdatesto undefined?Shoud be
Edit: I realised this wouldn't work because
setStatefunctions are asynchronousInstead you'll have to use a ref, i.e
you can also write a custom state hook wrapper eh... hook?