JavaScript 反应钩子背后的机制是如何工作的?
How does JavaScript mechanism behind react hooks work?
我的问题与 Javascript 使反应挂钩成为可能的机制有关。
React 的最新开发允许我们创建钩子,即。对于 React 状态,在像这样的简单函数中:
function App () {
const [someVar, setSomeVar] = useState('someVarDefaultValue');
return (
<div
onClick={() => setSomeVar('newValue')}>{someVar}
</div>
);
}
钩子 useState
returns 一个带有访问器和修改器的数组,我们在 App 函数中通过数组分解来使用它们。
所以在幕后,钩子看起来像(只是一个伪代码):
function useState(defaultValue) {
let value = defaultValue;
function setValue(val) {
value = val;
}
return [value, setValue];
}
当你在 JS 中尝试这种方法时,它不会起作用 - 如果你在某处使用 setValue
,从数组分解的值将不会更新。即使您使用 value
作为对象,而不是原始 defaultValue
.
我的问题是钩子机制在JS中是如何工作的?
根据我在 React sourcecode 中看到的内容,它使用 reducer 函数并使用 Flow 进行类型检查。为了理解全局,代码很难理解。
这个问题不是关于 how to write custom hooks in React。
在这个问题中回答的 React 状态管理上下文中钩子如何在幕后工作也不是问题:
状态值必须存储在 useState
函数之外,在组件实例的某些内部表示中,以便它 returns 跨调用持久结果。此外,设置该值必须导致在调用它的组件上重新呈现:
// useState must have a reference to the component it was called in:
let context;
function useState(defaultValue) {
// Calling useState outside of a component won't work as it needs the context:
if(!context) throw new Error("Can only be called inside render");
// Only initialize the context if it wasn't rendered yet (otherwise it would re set the value on a rerender)
if(!context.value)
context.value = defaultValue;
// Memoize the context to be accessed in setValue
let memoizedContext = context;
function setValue(val) {
memoizedContext.value = val;
// Rerender, so that calling useState will return the new value
internalRender(memoizedContext);
}
return [context.value, setValue];
}
// A very simplified React mounting logic:
function internalRender(component) {
context = component;
component.render();
context = null;
}
// A very simplified component
var component = {
render() {
const [value, update] = useState("it");
console.log(value);
setTimeout(update, 1000, "works!");
}
};
internalRender(component);
然后当 setValue
被调用时,组件重新渲染,useState
将再次被调用,并返回新值。
上面的例子非常简单,这里有一些 React 不同的地方:
(1) 状态不存储在“上下文属性”中,而是存储在链表中。每当调用 useState
时,链表都会前进到下一个节点。这就是为什么你不应该在分支/循环中使用钩子。
(2) setState 函数被缓存并且每次都返回相同的引用。
(3) 重新渲染不会同步发生。
我的问题与 Javascript 使反应挂钩成为可能的机制有关。
React 的最新开发允许我们创建钩子,即。对于 React 状态,在像这样的简单函数中:
function App () {
const [someVar, setSomeVar] = useState('someVarDefaultValue');
return (
<div
onClick={() => setSomeVar('newValue')}>{someVar}
</div>
);
}
钩子 useState
returns 一个带有访问器和修改器的数组,我们在 App 函数中通过数组分解来使用它们。
所以在幕后,钩子看起来像(只是一个伪代码):
function useState(defaultValue) {
let value = defaultValue;
function setValue(val) {
value = val;
}
return [value, setValue];
}
当你在 JS 中尝试这种方法时,它不会起作用 - 如果你在某处使用 setValue
,从数组分解的值将不会更新。即使您使用 value
作为对象,而不是原始 defaultValue
.
我的问题是钩子机制在JS中是如何工作的?
根据我在 React sourcecode 中看到的内容,它使用 reducer 函数并使用 Flow 进行类型检查。为了理解全局,代码很难理解。
这个问题不是关于 how to write custom hooks in React。
在这个问题中回答的 React 状态管理上下文中钩子如何在幕后工作也不是问题:
状态值必须存储在 useState
函数之外,在组件实例的某些内部表示中,以便它 returns 跨调用持久结果。此外,设置该值必须导致在调用它的组件上重新呈现:
// useState must have a reference to the component it was called in:
let context;
function useState(defaultValue) {
// Calling useState outside of a component won't work as it needs the context:
if(!context) throw new Error("Can only be called inside render");
// Only initialize the context if it wasn't rendered yet (otherwise it would re set the value on a rerender)
if(!context.value)
context.value = defaultValue;
// Memoize the context to be accessed in setValue
let memoizedContext = context;
function setValue(val) {
memoizedContext.value = val;
// Rerender, so that calling useState will return the new value
internalRender(memoizedContext);
}
return [context.value, setValue];
}
// A very simplified React mounting logic:
function internalRender(component) {
context = component;
component.render();
context = null;
}
// A very simplified component
var component = {
render() {
const [value, update] = useState("it");
console.log(value);
setTimeout(update, 1000, "works!");
}
};
internalRender(component);
然后当 setValue
被调用时,组件重新渲染,useState
将再次被调用,并返回新值。
上面的例子非常简单,这里有一些 React 不同的地方:
(1) 状态不存储在“上下文属性”中,而是存储在链表中。每当调用 useState
时,链表都会前进到下一个节点。这就是为什么你不应该在分支/循环中使用钩子。
(2) setState 函数被缓存并且每次都返回相同的引用。
(3) 重新渲染不会同步发生。