如何在useState中使用来自useEffect的异步返回值作为默认值?

11

我创建了一个简单的示例https://codesandbox.io/s/4zq852m7j0

正如您所看到的,我正在从远程源获取一些数据。我想使用返回值作为文本字段内的值。

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;
};

然而,在useState函数内部使用值是无效的。我认为useState仅在第一次渲染时使用默认值。在第一次渲染时,该值显然未设置,因为它是异步的。文本字段应该具有值bar,但实际上为空。

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>
  );
}

从远程获取值后,我希望能够在本地进行更改。

有什么想法吗?

3个回答

8
现在,useFetch 返回一个异步可用的值,您需要在远程值可用时更新 localState,为此可以编写一个 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);
  };

演示链接


3

这与在类组件中异步设置初始状态的情况完全相同:

state = {};

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

在初始渲染过程中,异步获取的状态可能无法使用。函数组件应该像类组件一样使用相同的技术,即有条件地渲染依赖于状态的子组件:

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

这样做就没有理由让useFetch拥有自己的状态,它可以与组件一起维护公共状态(参见示例):

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>
  );
}

bar 是一个空字符串(删除文本字段中的值)时,整个组件都会消失。 - zemirco
如果使用空字符串作为初始状态不能满足您的需求,请不要使用它。您可以使用 useState() 并进行 name != null && ... 检查。 - Estus Flask

1

无法将初始状态作为异步函数传递吗?

i.e

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接