In the code below, when I call _toggleSearch
I update 2 hooks simultaneously.
toggleSearchIsVisible
is a simple boolean, however, setActiveFilter
hook must pass in the previous searchIsVisible
state.
How can I be sure the other state hasn't updated yet when passed in? Or how else should I restructure everything? Previously with setState
I could've passed in the previous state easily.
const [activeFilter, setActiveFilter] = useState('SHOW_ALL');
const [searchIsVisible, toggleSearchIsVisible] = useState(false);
const _toggleSearch = () => {
setActiveFilter(searchIsVisible ? 'SHOW_SEARCH' : 'SHOW_ALL');
toggleSearchIsVisible(!searchIsVisible);
};
I've gone with this for now:
const _toggleSearch = () => {
if (searchIsActive) {
setActiveFilter('SHOW_ALL');
toggleSearchIsActive(false);
} else {
setActiveFilter('SHOW_SEARCH');
toggleSearchIsActive(true);
updateSearchValue('');
}
};
Any other suggestions appreciated!
Try using the useEffect
hook to deal with the side effects of toggling the searchIsVisible
boolean.
Here is an example:
const _toggleSearch = () => {
toggleSearchIsVisible(!searchIsVisible);
};
useEffect(() => {
setActiveFilter(searchIsVisible ? 'SHOW_ALL' : 'SHOW_SEARCH');
}, [searchIsVisible]);
You can see that I also passed [searchIsVisible]
to the useEffect
hook to optimize performance.
This will ensure that useEffect
is only triggered when searchIsVisible
is updated: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
Here is a demo: https://codesandbox.io/s/l2901jr68l
I hope this helps.
Note:
Also I switched the order of SHOW_ALL
and SHOW_SEARCH
in your conditional, because it would seem that SHOW_SEARCH
should be displayed when searchIsVisible
is false
, and SHOW_ALL
should be displayed when searchIsVisible
is true
, but if that's not the case just switch the order back.
If you encounter a situation about syncing two states, take a step back and see if one of the states can be derived from the other. It seems that in this case the two states you have that are essentially related, and one of them can indeed be derived from the other. So you actually don't need two state values, you only need one. Derived state should not be part of state as that leads to duplication of state and then you have to sync up the state values, which is what you are asking in your question.
In the examples below, I demonstrate how you can use either activeFilter
or searchIsVisible
as the single state to retain.
If you retain activeFilter
, the value of searchIsVisible
is derived from the and vice versa. The key is to set searchIsVisible
in depending on the value of activeFilter
.
activeFilter
as state const App = () => { const [activeFilter, setActiveFilter] = React.useState('SHOW_ALL'); const searchIsVisible = activeFilter !== 'SHOW_ALL'; const _toggleSearch = () => { setActiveFilter(activeFilter === 'SHOW_ALL' ? 'SHOW_SEARCH' : 'SHOW_ALL'); }; return ( <div> <p>Active Filter: {activeFilter}</p> <button onClick={_toggleSearch}>Toggle Search</button> {searchIsVisible && <div> <input placeholder="Search" /> </div>} </div> ); }; ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>
searchIsVisible
as state const App = () => { const [searchIsVisible, setSearchIsVisible] = React.useState(false); const activeFilter = searchIsVisible ? 'SHOW_SEARCH' : 'SHOW_ALL'; const _toggleSearch = () => { setSearchIsVisible(!searchIsVisible); }; return ( <div> <p>Active Filter: {activeFilter}</p> <button onClick={_toggleSearch}>Toggle Search</button> {searchIsVisible && <div> <input placeholder="Search" /> </div>} </div> ); }; ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.