skip to Main Content

I want to have an initial state in my component, but I need to set it based on a complex if/else statement.

Using nested tertiarry statements very soon becomes unreadable and unmanageable. And since states should be top-level statements, I can’t write if/else statements directly inside the component.

For example, let’s say I need to set the initial state for the selected country, based on some given props, from the local storage, from the URL, or from the session state, or from a cookie:

const SomeComponent = ({ useUrl, useLocaleStorage, useSessionStorage, useCookie }) => {
    const [initialCountry, setInitialCountry] = useState(/* logic to check where to read from, for the initial state */);

}

In the above example, I need to convert this simple JS, to react-style:

let initialCountry = 'uk'

if (useUrl) {
   // read from URL and set it
} else if (useCookie) {
   // read from cookie and set it
} else if (useSessionStorage) {
   // read from session storage and set it
} else if (useLocaleStorage) {
   // read from local storage and set it
}

I know I can create a simple state, and the use useEffect to initialze it. But that makes the state change multiple times. I don’t want that. I want the initial state to be created using the complex logic, not to be changed.

3

Answers


  1. Your question seems quite vague.
    But here are some options to consider:

    1. If possible use useMemo instead of useState. This will make sure you are only updating the object when needed (if you want you can only initialise once).
    2. If you really need the state use a function that calculates your initial state (something like const [initialCountry, setInitialCountry] = useState(getCountryState()); ). Maybe you can reuse this function to always return you the proper country state if you need to update it (so you can consider extending the functionality to return the updated state if ever needed).
    3. If initialising logic looks complex use a custom hook and, if needed to avoid to much inline code, consider combining this with the function mentioned at point 2
    4. This is a standalone recommendation: when possible consider having a constant with the possible values instead of a lot of boolean props.

    So instead of using something like

    const SomeComponent = ({ useUrl, useLocaleStorage, useSessionStorage, useCookie }) => {
      ...
      if (useUrl)...
    

    you could have something like

    const SomeComponent = (props) => {
      ...
      switch (props.sourceToUse) {
        case SOURCES.url:
          ...
    
    Login or Signup to reply.
  2. In your state you can set the value once:

    const [data, setData] = useState(yourFunction())
    
    function yourFunction(){
        if(..){
            return ..
        }    
    }
    

    And if you wanna use useEffect, you can add a ‘dependency array’:

    useEffect(() => {}, [dependency])
    

    When the dependency changes (and once on start), the useEffect will execute.

    Login or Signup to reply.
  3. There is no reason to make a single complex expression. useState accepts an initializer function, this function is only executed once, when the component is mounted. So this does not only make your code more readable, but probably also faster. Since you don’t need to read from cookie/storage and possibly parse JSON for each render.

    To quote the useState documentation:

    • If you pass a function as initialState, it will be treated as an initializer function. It should be pure, should take no arguments, and should return a value of any type. React will call your initializer function when initializing the component, and store its return value as the initial state. See an example below.
    const SomeComponent = ({ useUrl, useLocaleStorage, useSessionStorage, useCookie }) => {
        const [initialCountry, setInitialCountry] = useState(() => {
            if (useUrl) return ...;
            if (useCookie) return ...;
            if (useSessionStorage) return ...;
            if (useLocaleStorage) return ...;
        });
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search