我有这些没有任何反冲钩的部件。
const C = () => {
console.log('---->C')
return <Text>C</Text>
}
const B = () => {
console.log('--->B')
return <>
<Text>B</Text>
<C/>
</>
}
const A = () => {
console.log('-->A')
return <>
<Text>A</Text>
<B/>
</>
}
const App = () => {
console.log('->App')
return (
<RecoilRoot>
<A />
</RecoilRoot>
);
};
当我在控制台中运行应用程序时,会显示经过检查的日志:
LOG ->App
LOG -->A
LOG --->B
LOG ---->C
现在我将使用反冲钩突变并访问原子态
import { atom, useSetRecoilState, useRecoilState, useRecoilValue, RecoilRoot } from "recoil";
const atomTest = atom({
key: "abcatomTest",
default: "A"
})
const C = () => {
console.log('---->C')
const [value, set] = useRecoilState(atomTest)
return <>
<Text>C</Text>
</>
}
const B = () => {
console.log('--->B')
const set = useSetRecoilState(atomTest)
return <>
<Text>B</Text>
<C/>
</>
}
const A = () => {
console.log('-->A')
const value = useRecoilValue(atomTest)
return <>
<Text>A</Text>
<B/>
</>
}
const App = () => {
console.log('->App')
return (
<RecoilRoot>
<A />
</RecoilRoot>
);
};
我甚至不使用从useRecoilValue
、useSetRecoilState
、useRecoilState
返回的值和函数,如果我使用它,它可以正常工作,但在第一次渲染中,日志是:
LOG ->App
LOG -->A
LOG -->A
LOG ->App
LOG --->B
LOG ---->C
LOG ---->C
LOG --->B
LOG -->A
LOG ->App
LOG -->A
LOG --->B
LOG ---->C
为什么反冲会迫使包括root在内的多个组件重新渲染,我根本不会改变状态,而且在应用程序组件中也不依赖任何状态!
首先:React执行一个函数并不意味着组件实际上会重新渲染。React有一个提交和一个呈现阶段。在提交阶段,React进行更改并调用子组件,检查是否有新的内容需要呈现。在渲染阶段,React会检查是否存在实际需要重新渲染的组件。如果输出、钩子状态和道具相同,则不会重新渲染,即使React之前调用了您的函数组件。这就是您看到所有日志的原因。您检查的不是重新渲染,而是函数执行。
您的应用程序组件实际上具有要声明的依赖项,因为它呈现RecoilRoot
组件。当该组件发生更改时,React将再次进入提交阶段,并检查所有子级,以查看是否有更改。
由于每个组件都使用一个引用atomTest
原子的钩子,Recoil必须为该组件订阅该原子。因此,Recoil和React必须通过树来寻找变化。
如果你查看React Developer Tools的Profiler,你会发现没有实际的重新渲染,因为你的组件没有改变任何输出。