1

I have the next component in my react application:

import React, { useEffect, useState } from "react";
import AsyncSelect from "react-select/async";
import { ColourOption, colourOptions } from "./docs/data";

const App = () => {
  const [state, setState] = useState([]);

  useEffect(() => {
    setState(colourOptions);
  }, []);

  return (
    <AsyncSelect
      cacheOptions
      defaultOptions
      loadOptions={async () => new Promise((r) => r(state))}
    />
  );
};

export default App;

There i set colourOptions in useEffect and after that i read the state in loadOptions. Now the options don't appear when i open the select, but when i change loadOptions={async () => new Promise((r) => r(state))} to loadOptions={async () => new Promise((r) => r(colourOptions))} the dropdown items appear.
How to make my code workable in the first situation with state, using useEffect?
demo: https://codesandbox.io/s/codesandboxer-example-forked-b3857?file=/example.tsx:355-409

3 Answers 3

4

The thing is, state is set after the useEffect call (to test this, just map the state in the JSX and log each array index). The loadOptions function in react-select's async component appears to be memoized with only its props as dependencies, so you're not going to get a new loadOptions function just because you've set the state in your useEffect. In other words, upon a new render of your component the options will stay the same even though state has been updated. The question is, why use useEffect at all?

It seems to me like you're calling useEffect in your example to simulate an asynchronous call, like you'd do when you want to fetch some data. Normally, when people want to fetch data, they'll throw the async call into a useEffect and fetch the data after the first render. The thing is, the loadOptions function exposed by react-select's async component already provides this functionality - that is, it will fetch your options for you asynchronously at first blush right when you need them, rather than wait an extra step for a state update that may force you to programmatically re-instantiate the loadOptions function (by changing a prop like defaultOptions or something possibly even more hacky.

TLDR just use the loadOptions function as your asynchronous data fetcher rather than wait for useEffect.

Sign up to request clarification or add additional context in comments.

2 Comments

the idea is that i can not use a state created with useState hook inside loadOptions,if that state is updated with useEffect, but i need to use state there. How to do that? I
Hi @Asking, in that case, as my answer describes, go ahead and try passing the state value as defaultOptions - this way, you are telling the component that it should rerender once state has been loaded from your useEffect. I think you'll discover that this has its own set of drawbacks, though I'm still unclear on what exactly you're trying to accomplish. Hope this helps!
0

First of all, the state is asynchronous it means you can not get its value immediately after you set the state.

So this problem can be fixed by initializing state.

const [state, setState] = useState(colourOptions);

1 Comment

i need the solution with useEffect because colourOptions could be different on first render and useEffect is realy important here. Do you have a solution for that?
-1

Since the state setting is asynchronous you can try adding a loading screen while the options state remains undefined,something like

return (
{state?
    <AsyncSelect
      cacheOptions
      defaultOptions
      loadOptions={async () => new Promise((r) => r(state))}
    />
:
<SomeLoadingScreen/>
}
  );

2 Comments

there is a diferent issue, your answer does not work
what is the specific issue then,if i know it i can try to help @Asking

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.