我在这里找不到类似的问题,所以就这样:
我创建了一个自定义钩子@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)
在那里已更新,但状态未更新。
我认为这是由于异步而发生的吗?但是如何解决呢?
谢谢!
答案 0 :(得分:0)
我可以解决问题,但是,我不是100%认为这是最好/正确的方法。据我所知,由于异步性,我仍在读取旧状态值,解决此问题的一种方法是在useEffect
中设置状态。我会:
const [budgetInfo] = useBudget(resource, type);
const [appState, setAppState] = useState({ budget: budgetInfo.budget_amount });
useEffect(
() => {
setAppState({ budget: budgetInfo.budget_amount });
}, [budgetInfo]);
但是它现在正在工作!
答案 1 :(得分:0)
使用useEffect
安排的效果不会阻止浏览器更新屏幕-这就是在屏幕上显示0
(initialState
)的原因。取值后,组件保持不变,其自身状态(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几乎没有优势-更精确的命名和进行单个更新的能力。