From 2181c9264d78a56e0583cde47efd8be443bad7a9 Mon Sep 17 00:00:00 2001 From: byt3h3ad Date: Fri, 24 May 2024 12:59:05 +0530 Subject: [PATCH] add: react/finite-state-machine.md --- react/finite-state-machine.md | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 react/finite-state-machine.md diff --git a/react/finite-state-machine.md b/react/finite-state-machine.md new file mode 100644 index 0000000..4cabd3d --- /dev/null +++ b/react/finite-state-machine.md @@ -0,0 +1,54 @@ +# Simplify Your Components with Finite State Machines and Derived States + +Consider a common situation of a React component with multiple UI states such as `loading`, `error`, and `success`. The common paatern is to use multiple `useState` hooks to manage these states. This results in code that is hard to read and error-prone - + +```js +const MyComponent = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(false) + const [success, setSuccess] = useState(false) + + return ( +
+ {loading && !error && !success &&

Loading...

} + {error && !loading && !success &&

Error occurred

} + {success && !loading && !error &&

Operation completed successfully

} +
+ ) +} +``` + +These states are **distinct from each other**. When `loading` is true, the `error` and `success` states should be false. Using multiple useState hooks can cause unexpected behaviors, like accidentally setting two states to true simultaneously. + +Instead, consider using the ["finite state machine" (FSM) pattern](https://en.wikipedia.org/wiki/Finite-state_machine). A FSM allows only a finite number of states. In the UI example above, a single useState can manage the current state more robustly and with less risk of error, as shown here: + +```js +import { useState } from 'react' + +type State = 'loading' | 'error' | 'success' + +const MyComponent = () => { + const [state, setState] = useState('loading') + + const handleClick = () => { + setState('loading') + // Simulate an async operation + setTimeout(() => { + setState('success') + }, 2000) + } + + return ( +
+ {state === 'loading' &&

Loading...

} + {state === 'error' &&

Error occurred

} + {state === 'success' &&

Operation completed successfully

} + +
+ ) +} +``` + +An even better way would be to use something like [Tanstack Query](https://tanstack.com/query/latest/docs/framework/react/overview) to fetch data. `useQuery` eliminates the need for separate `useState` hooks for `loading`, `error`, and `success` states. + +[source](https://www.nico.fyi/blog/you-dont-need-usestate-in-react)