'Keep a component on global state change - i.e. a "OK" intermediate view
This question is somewhat complicated to describe in a simple sentence. Allow me to explain.
Note that this is a problem I encountered several times on different occasions, so this is more of a theoretical question than a specific one.
I have a main component that returns different component based on the Redux (or similar) state.
Something like this
/* NOTE : Redux parts simplified to a simpler version for the sake of simplicity in this example */
function MainComponent(props) {
if (reduxState.someField === null) {
return <SubComponent1 />
}
else {
return <SubComponent2 />
}
}
function SubComponent1(props) {
useEffect(() => {
doSomethingAsync().then(() => {
/* set reduxState.someField to some value */
});
})
if (reduxState.someField === null) {
return "Async task in progress...";
}
else {
return (
<div>
Change applied ! Press OK to continue.
<button onClick={() => {
/* Somehow warn the MainComponent that SubComponent1 has done */
}}>OK</button>
</div>
);
}
}
function SubComponent2(props) {
return "Redux field is set";
}
SubComponent1 will change the redux state somehow - directly or indirectly. This means that the MainComponent should return SubComponent2. But I don't want that to happen.
What I want to achieve is: after the redux state get changed, Subcomponent1 renders a message stating that the change has been done, and waits for the user for an action. In other terms, some way to say "Change applied ! Press OK to continue", then allow the MainComponent to render SubComponent2, not before.
I know several ways to circumvent this problem by putting some state values in MainComponent or in the redux state, or not changing the redux state until the said [OK] button is pressed. However, this is not always feasible - or at least very difficult.
What I would like to create is an intermediate component that "locks" the change somehow and be used in a generic way anywhere I need it, instead of polluting my components or global state with values that are hard to maintain.
The MainComponent would then look like this (or something similar):
function MainComponent(props) {
let subComponent;
if (reduxState.someField === null) {
subComponent = <SubComponent1 />;
}
else {
subComponent = <SubComponent2 />;
}
return <LockedChange>{subComponent}</LockedChange>;
}
How would you do that ?
(I realize this is a quite complex and difficult to answer question. I don't expect a one-fits-all solution, just curious how you deal with this kind of problem)
Solution 1:[1]
Look into the concept of state machines and think about this as model-view-controller. The state machine is in the controller and it's pulling the strings. You view should be really dumb and only responsible for rendering, and keep state in the model.
To keep the view dumb, use composition. The controller will give the view a function (send the function in the component's props, wrapped in useCallback() if you like) and say "Call this function when you're done". Wire it up to the OK button. The view doesn't know what the function does, it just calls it when someone pokes the OK button.
And in that function you will call "dispatch" or similar to alter the state machine and advance to the next step.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Dave |
