我注意到当我使用react钩子时,子组件的状态更改不会重新呈现没有状态更改的父组件.这个代码沙箱可以看到:https://codesandbox.io/s/kmx6nqr4o
由于缺乏将组件作为参数传递给钩子,或者作为绑定上下文,我错误地认为反应钩子/状态更改只是触发整个应用程序重新呈现,就像秘银的工作方式,以及React的设计原则所述:
React以递归方式遍历树,并在单个tick中调用整个更新树的渲染函数.
相反,看起来反应钩子知道它们与哪个组件相关联,因此,渲染引擎知道只更新那个单独的组件,并且从不调用render
其他任何东西,反对React的设计原则文档上面所说的.
钩子和组件之间的关联如何完成?
这个关联如何使反应知道只调用render
状态改变的组件,而不是那些没有的组件?(在代码沙箱中,尽管子状态发生了变化,但从render
不调用父元素)
当您将useState和setState的用法抽象为自定义钩子函数时,此关联如何仍然有效?(正如代码沙箱与setInterval
钩子一样)
似乎答案就在这条路径下的resolveDispatcher,ReactCurrentOwner,react-reconciler.
管理员请注意这个问题
这个问题不是关于如何在React中编写自定义钩子。
在这个问题中回答的React状态管理的上下文中,钩子如何在后台运行也不是问题:React Hooks-后台发生了什么?
我的问题与使反应挂钩成为可能的Javascript机制有关。
-注释结尾-
React的最新发展使我们能够创建钩子。对于React状态,在以下简单函数中:
function App () {
const [someVar, setSomeVar] = useState('someVarDefaultValue');
return (
<div
onClick={() => setSomeVar('newValue')}>{someVar}
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
挂钩useState
返回带有访问器和变量的数组,我们通过App函数内部的数组分解来使用它们。
因此,在幕后,该钩子看起来像(只是一个伪代码):
function useState(defaultValue) {
let value = defaultValue;
function setValue(val) {
value = val;
}
return [value, setValue];
}
Run Code Online (Sandbox Code Playgroud)
当您在JS中尝试这种方法时,它将无法正常工作-如果您在setValue
某处使用,从数组分解的值将不会更新。即使您将value
用作对象,也不能使用Primitive defaultValue
。
我的问题是挂钩机制在JS中如何工作?
从我在React 源代码中看到的内容来看,它使用reducer函数和对Flow进行类型检查。对于我来说,要理解全局,代码很棘手。
我在 React 官方文档或 blagosphere 上还没有找到任何提及这一点的信息。
我认为当你有多个状态变量时你可以而且通常应该做这样的事情:
function MyComponent() {
const [foo, setFoo] = useState(0);
const [bar, setBar] = useState(1);
return (
<div>
<div onClick={() => setFoo(foo+1)}>{foo}</div>
<div onClick={() => setBar(bar+1)}>{bar}</div>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
是否允许并鼓励这样做,而不是使用useState
一个包含state
字段foo
和的包罗万象的对象来调用一次bar
?如果允许并鼓励这样做,那么useState
每次调用时如何知道它是指已存储的foo
还是已存储的bar
?
我也有基本相同的问题useCallback
。我想知道,如果我useCallback
在同一个组件中调用两次以创建两个不同的回调,如何知道useCallback
我要引用之前定义的函数与创建新函数,并且如果引用已使用的函数,则需要返回记忆的函数的版本,它如何知道两者中的哪一个?特别是如果两个回调具有相同的依赖项列表?