【问题标题】:Promise function delays state variablePromise 函数延迟状态变量
【发布时间】:2021-12-30 00:46:42
【问题描述】:

如何正确地从 promise 函数中存储值而不延迟?

我正在尝试使用 useEffect 挂钩,但我的状态仍然延迟。

如果用户正在验证他的购物车,可能会应用错误的税款。

useEffect(() => {
SalesTax.getSalesTax(country, region).then((tax) => {
      setTax(tax.rate);
    });
}, [region]);
      

<RegionDropdown
            country={country}
            className="capitalize input"
            value={region}
            onChange={(val) => {
              setRegion(val);
            }}
            required
            countryValueType="short"
            valueType="short"
          />

【问题讨论】:

  • 你没有。 SalesTax.getSalesTax 是异步的,在 promise 完成之前,没有任何价值。找到一种向用户表明这一点的方法,例如通过显示“税收负担”指示器。
  • (打个比方:) 我以前在大学也遇到过类似的问题。我和我的女朋友会在电话里聊几个小时。我会请她过来,但这是在手机之前,所以出于显而易见的原因,在我们挂断电话之前,她不能离开宿舍来看我。除非我们结束谈话,否则我们不可能见面。这个故事的寓意是,如果你错过了它,你必须等待(挂断电话)异步事情(去另一个房间)发生,然后才能解决承诺(kissy Kissy)。

标签: javascript reactjs promise


【解决方案1】:

你应该这样做:

const [loading, setLoading] = useState(false);

useEffect(() => {
    setLoading(true);
    SalesTax.getSalesTax(country, region).then((tax) => {
        setTax(tax.rate);
        setLoading(false);
    });
}, [region]);

if (loading) {
    return <p>Loading...<p/>;
}
      

这是在 React 中处理异步操作的正常方式。

【讨论】:

  • 这就是我刚刚尝试实现的,但是当我尝试在承诺中设置 cart.taxPrice = tax 时,我的 redux 不会看到任何差异,当我将它设置在外面时,我面临同样的延迟。
  • 所以你使用的是redux,还是本地状态?如果是redux,则需要dispatch一个action,这样reducer才能看到。
  • 问题解决了谢谢 :)
【解决方案2】:

您将使用大量异步值,那么制作一个诸如useAsync 之类的钩子怎么样?

function useAsync(f, [_0, _1, _2, _3, _4]) {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
  const [result, setResult] = useState(null)
  useEffect(_ => {
    setLoading(true)
    Promise.resolve(f(_0, _1, _2, _3, _4))
      .then(setResult, setError)
      .finally(_ => setLoading(false))
  }, [f, _0, _1, _2, _3, _4])
  return {loading, error, result}
}

现在在你的组件中使用你的钩子 -

function MyComponent({country, region}) {
  const {loading, error, result} =
    useAsync(SalesTax.getSalesTax, [country, region])
  if (loading)
    return <p>Loading...</p>
  else if (error)
    return <p>Error: {error.message}</p>
  else
    /* result is usable here */
    return <RegionDropdown .../>
}

_0, _1, _2, ... 是必需的,因此 ESLint 可以静态分析依赖关系。在未来的版本中,也许可以使用数组。另一种选择是为此钩子禁用 ESLint,但请注意这是 discouraged by Dan Abramov of React -

function useAsync(f, args) {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
  const [result, setResult] = useState(null)
  useEffect(_ => {
    setLoading(true)
    Promise.resolve(f(...args))
      .then(setResult, setError)
      .finally(_ => setLoading(false))
  },
  // eslint-disable-next-line react-hooks/exhaustive-deps
  [f, ...args])
  return {loading, error, result}
}

【讨论】:

  • 这不是 React,这是一条 linter 规则。在这种情况下可以(并且应该)忽略哪个。或者也许像function useAsync(...args) { … useEffect(() =&gt; { const f = args.shift(); f(...args) … }, args); } 这样的解决方法被linter 接受了?如果一切都失败了,请避免直接接受参数并要求使用 useAsync(useCallback(() =&gt; f(a, b, c), [f, a, b, c])) 而不是 useAsync(f, a, b, c)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-29
  • 1970-01-01
  • 2013-02-03
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
相关资源
最近更新 更多