我刚刚说过尝试使用React钩子,但是我还没有找到解决以下问题的方法。假设我有两个用于获取数据的自定义钩子。为简单起见,假设第一个不带参数,第二个不带参数,如下所示:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// fetching takes 3 secs
function useFetch1() {
const [text, setText] = useState("")
useEffect(() => {
const test = async () => {
await sleep(3000)
setText("text1")
}
test()
}, [])
return text
}
// fetching takes 1 sec
function useFetch2(input) {
const [text, setText] = useState("")
useEffect(() => {
const test = async () => {
await sleep(1000)
setText(input + "text2")
}
test()
}, [input])
return text
}
这使我可以独立使用每个挂钩。到目前为止,一切都很好。但是,当第二次获取的参数取决于第一次获取的输出时,会发生什么。特别是,假设我的App组件是这样的:
function App() {
const text1 = useFetch1()
const text2 = useFetch2(text1) // input is dependent on first fetch
// renders text2 and then text1text2
return (
<div>
{text2}
</div>
)
}
在这种情况下,渲染器将首先显示“ text2”,然后(2秒后),将显示“ text1text2”(即首次提取完成时)。有没有一种方法可以确保仅在useFetch2
完成后才调用useFetch1
?
答案 0 :(得分:1)
您可以实现所需的行为,但是: 设计上,必须在每个渲染器上调用挂钩函数-不允许有条件地调用挂钩,React无法处理它。
您可以在钩子内实现逻辑,而不是有条件地调用钩子,例如,useFetch1
可以返回请求的状态,该状态可以在另一个钩子中用于有条件地基于该请求执行某些操作。
示例:
function useFetch1() {
const [text, setText] = useState("")
// a bool to represent whether the fetch completed
const isFinished = useState(false)
useEffect(() => {
const test = async () => {
await sleep(3000)
setText("text1")
}
test()
}, [])
return {text, isFinished} // Return the isFinished boolean
}
function useFetch2(input, isFetch1Finished) {
const [text, setText] = useState("")
useEffect(() => {
if (!isFetch1Finished) {
return; // fetch1 request not finished, don't fetch
}
const test = async () => {
await sleep(1000)
setText(input + "text2")
}
test()
}, [input])
return text
}
function App() {
const {text: text1, isFinished} = useFetch1()
const text2 = useFetch2(text1, isFinished) // input is dependent on first fetch, but is aware whether the first fetch is finished or not.
return (
<div>
{text2}
</div>
)
}
现在,您可以在第二次访存中使用isFinished
中的useFetch1
布尔标志来确定是否执行某项操作。
更好的方法
这完全取决于您的用例,但是您可能不希望将2个钩子的逻辑耦合在一起。我建议最好将useFetch2
放在一个单独的组件中,该组件根据状态useFetch1
有条件地呈现。
return (
{isFetch1Finished && <SecondComponent text={text1}>}
)
现在,通过在第一个请求完成后有条件地呈现第二个组件,简化了钩子逻辑。与第一种方法相比,这是一个更好的设计。
您是否还需要2个钩子? 问问自己是否甚至需要两个钩子,使用promises在单个钩子中实现同步行为将是微不足道的。
示例:
useFetch(() => {
const [state, setState] = useState("");
useEffect(() => {
fetch('http://..').then(res1 => {
fetch('http://..').then(res2 => {
// In this scope you have both `res1` and `res2`.
setState(res1 + res2);
})
})
}, [])
return state;
})