React: 只有当另一个状态达到特定值时才更新状态。

huangapple go评论64阅读模式
英文:

React: update state only once, when another state reaches certain value

问题

以下是您要翻译的代码部分:

import { useEffect, useState } from "react";

import "./styles.css";

function useAsyncState() {
  const [status, setStatus] = useState("idle");

  function trigger(value) {
    setStatus(`sending ${value}`);
    setTimeout(function () {
      setStatus("done");
    }, 1500);
  }

  return [status, trigger];
}

export default function App() {
  const [value, setValue] = useState(0);
  const [status, trigger] = useAsyncState();

  useEffect(() => {
    if (status === "done") {
      setValue(value - 1);
    }
  }, [status, value]);

  return (
    <div className="App">
      <p>
        status: {status}
        <button onClick={() => trigger(value)}>send & decrement</button>
      </p>
      <p>
        value: {value}
        <button onClick={() => setValue(value + 1)}>increment</button>
      </p>
    </div>
  );
}

希望这对您有所帮助。如果您需要更多信息,请随时提问。

英文:

Here's my code https://codesandbox.io/s/heuristic-cannon-lvse23?file=/src/App.js

import { useEffect, useState } from &quot;react&quot;;

import &quot;./styles.css&quot;;

function useAsyncState() {
  const [status, setStatus] = useState(&quot;idle&quot;);

  function trigger(value) {
    setStatus(`sending ${value}`);
    setTimeout(function () {
      setStatus(&quot;done&quot;);
    }, 1500);
  }

  return [status, trigger];
}

export default function App() {
  const [value, setValue] = useState(0);
  const [status, trigger] = useAsyncState();

  useEffect(() =&gt; {
    if (status === &quot;done&quot;) {
      setValue(value - 1);
    }
  }, [status, value]);

  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;p&gt;
        status: {status}
        &lt;button onClick={() =&gt; trigger(value)}&gt;send &amp; decrement&lt;/button&gt;
      &lt;/p&gt;
      &lt;p&gt;
        value: {value}
        &lt;button onClick={() =&gt; setValue(value + 1)}&gt;increment&lt;/button&gt;
      &lt;/p&gt;
    &lt;/div&gt;
  );
}

I have some kind of async action wrapped into a custom hook useAsyncState (simplified version of some real hook from my dependencies).

The problem is, I want to update value only once, when async action turns into done state.

However, changing state rerenders the component and since status is still done, value changes again, leading to endless loop of decrementing.

Also, action can be triggered again and I want to decrement value, when it's done again.

If I had an original Promise, I could do it in then callback, but I have only a hook like this.

Also, using useEffect delays value update to the next render, so it takes two renders to show decremeneted value. It's not a big deal, but it would be nice to do it in single render.

Is it ever possible to do it nice with such a custom hook? Or using raw Promises is the only way?

答案1

得分: 1

你可以使用功能性更新代替:

如果新状态是使用先前状态计算的,您可以将一个函数传递给setState。该函数将接收先前的值,并返回更新后的值。

useEffect(() => {
  if (status === "done") {
    setValue((prevValue) => prevValue - 1);
  }
}, [status]);
英文:

You can use a Functional Update instead:

> If the new state is computed using the previous state, you can pass a function to setState. The function will receive the previous value, and return an updated value.

useEffect(() =&gt; {
  if (status === &quot;done&quot;) {
    setValue((prevValue) =&gt; prevValue - 1);
  }
}, [status]);

huangapple
  • 本文由 发表于 2023年2月16日 05:23:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75465561.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定