最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How use async return value from useEffect as default value in useState? - Stack Overflow

programmeradmin0浏览0评论

I've created a simple example .

As you can see I'm fetching some data from a remote source. I'd like to use the return value as the value inside my textfield.

const useFetch = () => {
  const [value, setValue] = useState("");

  useEffect(
    async () => {
      const response = await fetch("");
      const data = await response.json();
      setValue(data.args.foo);
    },
    [value]
  );

  return value;
};

However using the value inside the useState function does not work. I think useState uses the default value only on first render. When first rendering the value is obviously not set since it's async. The textfield should have the value bar but it is empty.

function App() {
  const remoteName = useFetch();
  // i want to see the remote value inside my textfield
  const [name, setName] = useState(remoteName);

  const onChange = event => {
    setName(event.target.value);
  };

  return (
    <div className="App">
      <p>remote name: {remoteName}</p>
      <p>local name: {name}</p>
      <input onChange={onChange} value={name} />
    </div>
  );
}

After fetching the value from remote I'd like to be able to change it locally.

Any ideas?

I've created a simple example https://codesandbox.io/s/4zq852m7j0.

As you can see I'm fetching some data from a remote source. I'd like to use the return value as the value inside my textfield.

const useFetch = () => {
  const [value, setValue] = useState("");

  useEffect(
    async () => {
      const response = await fetch("https://httpbin.org/get?foo=bar");
      const data = await response.json();
      setValue(data.args.foo);
    },
    [value]
  );

  return value;
};

However using the value inside the useState function does not work. I think useState uses the default value only on first render. When first rendering the value is obviously not set since it's async. The textfield should have the value bar but it is empty.

function App() {
  const remoteName = useFetch();
  // i want to see the remote value inside my textfield
  const [name, setName] = useState(remoteName);

  const onChange = event => {
    setName(event.target.value);
  };

  return (
    <div className="App">
      <p>remote name: {remoteName}</p>
      <p>local name: {name}</p>
      <input onChange={onChange} value={name} />
    </div>
  );
}

After fetching the value from remote I'd like to be able to change it locally.

Any ideas?

Share Improve this question edited Nov 21, 2018 at 20:47 skyboyer 23.7k7 gold badges61 silver badges71 bronze badges asked Nov 14, 2018 at 10:59 zemircozemirco 16.4k8 gold badges66 silver badges100 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 8

Now that useFetch returns a value that is available asynchronously, what you need is to update localState when the remoteValue is available, for that you can write an effect

const remoteName = useFetch();
  // i want to see the remote value inside my textfield
  const [name, setName] = useState(remoteName);
  useEffect(
    () => {
      console.log("inside effect");
      setName(remoteName);
    },
    [remoteName] // run when remoteName changes
  );

  const onChange = event => {
    setName(event.target.value);
  };

Working demo

This is exactly same case as setting initial state asynchronously in class component:

state = {};

async componentDidMount() {
  const response = await fetch(...);
  ...
  this.setState(...);
}

Asynchronously retrieved state cannot be available during initial render. Function component should use same technique as class component, i.e. conditionally render children that depend on a state:

  return name && <div className="App">...</div>;

This way there's no reason for useFetch to have its own state, it can maintain common state with the component (an example):

const useFetch = () => {
  const [value, setValue] = useState("");

  useEffect(
    async () => {
      const response = await fetch("https://httpbin.org/get?foo=bar");
      const data = await response.json();
      setValue(data.args.foo);
    },
    [] // executed on component mount
  );

  return [value, setValue];
};

function App() {
  const [name, setName] = useFetch();

  const onChange = event => {
    setName(event.target.value);
  };

  return name && (
    <div className="App">
      <p>local name: {name}</p>
      <input onChange={onChange} value={name} />
    </div>
  );
}

Is it not possible to pass the initial state as an async function?

i.e

 const [value, setValue] = useState(async () => fetch("https://httpbin.org/get?foo=bar").json().args.foo);
发布评论

评论列表(0)

  1. 暂无评论