This is a continuation to https://dev.to/acsreedharreddy/when-could-should-we-merge-two-states-3e60
React Component is a function that takes in props, state and returns the view for that particular state and props.
f(props,state) => view
So our component has to handle all the possible types of props and states.
Let us create a Post component:
function Post({ id }) {
const [{ loading, error, data }, dispatch] = useReducer(reducer, {
loading: true,
error: null,
data: null,
});
useEffect(/* Load the data */);
return (
<div>
{loading && <Loading />}
{error && <Error />}
{data && <Body data={data} />}
</div>
);
}
We wanted the component to either render
Loading
orError
orBody
component.
But the issue with this component is:
- The Component would render both the
Loading
component andData
component when the state is{loading: true, data: "...", error: null}
.
Why does this happen?
The total number of possible states for the above component are
2(loading true | false) * 2(data | null) * 2(error | null) = 8 states
Of these 8 states only three are valid states
-
{loading: true, data: null, error: null}
when the data is loading. -
{loading: false, data:{...}, error: null}
when the data is loaded. -
{loading: false, data: null, error: {...}}
when there is an error.
When the state is anything other than the above three, our component renders an inconsistent View.
I could think of two ways to prevent invalid states:
- Write code more carefully so that we would never have inconsistent states. But we would not be 100% sure.
-
Make illegal states impossible to represent so that this type of state
{loading: true, data: {...}, error: null }
is impossible to create.
How can we Make illegal states impossible to represent?
We can achieve this with the help of Sum Type in a type system.
type state =
|{type:"Loading"}
|{type:"Error",error:string}
|{type:"Data",data:string}
It is called as an Union(TypeScript), Variant(ReScript).
So now the state could be one of the above three types. Then the total number of possible types of states come down to
1(Loading) + 1(Error) + 1(Data) = 3 states.
Since we have made illegal states impossible to represent, State will always be a valid one and we just have to create a React component which deals with three types of states.
The component becomes
type state =
|{type:"Loading"}
|{type:"Error",error:string}
|{type:"Data",data:string}
function Post({ id }) {
const [state, dispatch] = useReducer(reducer, {
type: "Loading",
});
useEffect(/* Load the data */);
switch (state.type) {
case "Loading":
return <Loading />;
case "Error":
return <Error />;
case "Data":
return <Data data={state.data} />;
}
}
Here we reduced the possible states from 8 to 3. But in our real-world scenarios, the numbers would be much larger than these and by reducing the possible states we reduce the complexity of the component.
Top comments (0)