具有先前返回的自定义钩子值的setState

时间:2019-02-22 19:29:14

标签: reactjs react-hooks

我在这里找不到类似的问题,所以就这样: 我创建了一个自定义钩子@tailrec final def fn(str: String): Option[String] = { Option(str).filter(_.nonEmpty).flatMap { v => fn(v.drop(1)) } } @tailrec final def fn2(str: String): Option[String] = { Option(str).filter(_.nonEmpty) match { case None => None case Some(v) => fn2(v.drop(1)) } } 来获取一些数据。

useBudget

在使用该钩子的组件上,我有这样的东西:

const initalState = {
    budget_amount: 0,
};

const useBudget = (resource: string, type: string) => {
    const [budgetInfo, setBudget] = useState(initalState);
    useEffect(
      () => {
          (async (resource, type) => {
              const response = await fetchBudgetInfo(resource, type);
              setBudget(response);
          })(resource, type);
    }, []);

    return [budgetInfo];
};

问题是:提取后,此组件的初始状态不会更新。 const [budgetInfo] = useBudget(resource, type); const [budgetForm, setBudgetForm] = useState({ warningMsg: null, errorMsg: null, budget: budgetInfo.budget_amount }); 最初使用budget进行渲染并保持这种状态。如果之后是0,则console.log(budgetInfo)在那里已更新,但状态未更新。

我认为这是由于异步而发生的吗?但是如何解决呢?

谢谢!

2 个答案:

答案 0 :(得分:0)

我可以解决问题,但是,我不是100%认为这是最好/正确的方法。据我所知,由于异步性,我仍在读取旧状态值,解决此问题的一种方法是在useEffect中设置状态。我会:

  const [budgetInfo] = useBudget(resource, type);
  const [appState, setAppState] = useState({ budget: budgetInfo.budget_amount });

  useEffect(
    () => {
      setAppState({ budget: budgetInfo.budget_amount });
  }, [budgetInfo]);

但是它现在正在工作!

工作示例:https://stackblitz.com/edit/react-wiewan?file=index.js

答案 1 :(得分:0)

使用useEffect安排的效果不会阻止浏览器更新屏幕-这就是在屏幕上显示0initialState)的原因。取值后,组件保持不变,其自身状态(budgetForm)不变。

一旦budgetInfo被获取,您的解决方案就会更新组件的状态,从而触发重新渲染,该方法可以工作,但似乎是一种解决方法。

useBudget可以单独使用:

const useBudget = (resource, type) => {
  const [budgetInfo, setBudget] = useState(initalState);

  const fetchBudgetInfo = async () => {
    const response = await (new Promise((resolve) => resolve({ budget_amount: 333 })))
    setBudget(response)
  }

  useEffect(() => {
    fetchBudgetInfo(resource, type)
  }, [])

  return budgetInfo
};

const App = props => {
  const { budget_amount } = useBudget('ok', 'ok')

  return (
    <h1>{budget_amount}</h1>
  );
}

fetchBudgetInfo被拆分,因为如果我们使效果函数异步(useEffect(async () => { ... })),它将隐式返回一个promise,这与它的设计背道而驰-唯一的返回值必须是一个将用于清理。 Docs ref

或者,考虑在没有自定义钩子的情况下检索数据:

const fetchBudgetInfo = async (resource, type) => {
  const response = await fetch(resource, type)
  return response
}

useEffect(() => {
  const response = fetchBudgetInfo(resource, type)
  setAppState((prevState) => { ...prevState, budget: response.budget_amount });
}, []);

值得注意的是,我们正在手动将旧状态与新值合并,如果appState包含多个值,这是必要的-这是因为useState不会浅合并对象(就像this.setState ),而是完全替换状态变量。 Doc ref

在某种程度上相关的注释上,使用对象来保持状态没有错,但是using multiple state variables几乎没有优势-更精确的命名和进行单个更新的能力。