- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
任何人都可以帮助我了解功能性 cmp 如何在状态发生变化时重新渲染。
引用下面的例子
function App() {
const [count, updateCount] = useState(0);
return (
<div className="App">
<h1>{count}</h1>
<button onClick={() => updateCount(count + 1)}>Update</button>
</div>
);
}
如果我将它与基于类的 React 组件进行比较,那么我们在类中有渲染函数,我相信只要状态或 Prop 发生变化,它就会被触发(必须有生命周期函数链和其中之一将是 this.render())
但是上面的代码结构 App
是一个功能组件,在 App 内部我们正在改变状态/计数,react 如何知道在 updateCount/setter 函数之后,App/(或其父函数)应该再打电话吗?我的意思是我们没有将 App 函数的引用正确传递给 useState。
最佳答案
在探讨 hooks 的区别之前,让我们先看看类是如何处理状态更新的。
当你调用基类的setState
方法时,它enqueues a state change .
this.updater.enqueueSetState(this, partialState, callback, 'setState');
它使用的 updater
对象 is defined here .我们看一下enqueueSetState
的实现。
先吧gets a fiber
使用 getInstance
函数,它是广泛命名的 get
function 的别名.
const fiber = getInstance(inst);
它的名字有点晦涩,但它所做的只是获取一个对象实例(您的类组件),并返回其 _reactInternals
属性值。
它创建一个 update
对象,其中 payload
是传递给 setState
的参数。然后它会安排此更新对象而不执行它,并使用 scheduleUpdateOnFiber
标记需要重新渲染的组件。
const update = createUpdate(eventTime, lane);
update.payload = payload;
if (callback !== undefined && callback !== null) {
if (__DEV__) {
warnOnInvalidCallback(callback, 'setState');
}
update.callback = callback;
}
const root = enqueueUpdate(fiber, update, lane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, lane, eventTime);
entangleTransitions(root, fiber, lane);
}
随着组件的更新(由 setState
触发的渲染以我们的元素作为根开始),将处理先前安排的更新队列。
它calls updateClassInstance
两者都执行类的生命周期方法,并返回组件是否需要重新渲染。
shouldUpdate = updateClassInstance(
current,
workInProgress,
Component,
nextProps,
renderLanes,
);
processUpdateQueue(workInProgress, newProps, instance, renderLanes);
如果状态发生变化,它将继续渲染组件。
与在内部管理自己状态的类组件相反,函数组件依赖调用钩子(Hook)让 React“为你”存储状态。
每次调用 useState
(或任何其他内部依赖于存储值的 Hook )都会将这段状态添加到每个组件的链表中。
React 完全依赖于此列表的顺序来为后续渲染过程中的每个 Hook 检索正确的值。这就是为什么你只能在顶层使用钩子(Hook),而不能在循环/条件中使用。否则 React 无法知道哪些数据属于哪个钩子(Hook)调用。
React hooks 每个都有 2 个实现,它们在内部切换。一个用于组件安装时,一个用于更新。这是有道理的,因为这两种情况的逻辑完全不同。
在第一次呈现时,它使用mountState
.
function mountState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const hook = mountWorkInProgressHook();
// ...
mountWorkInProgressHook
是在链表中创建 Hook 调用条目的地方。
if (workInProgressHook === null) {
// This is the first hook in the list
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
// Append to the end of the list
workInProgressHook = workInProgressHook.next = hook;
}
下一页 mountState
initializes根据 useState
的参数的状态。
if (typeof initialState === 'function') {
// $FlowFixMe: Flow doesn't like mixed types
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
它还会创建一个更新队列,类似于类组件的内部更新队列。
const queue: UpdateQueue<S, BasicStateAction<S>> = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: (initialState: any),
};
hook.queue = queue;
您返回的 setState
函数会在您调用它时将参数放入队列中。
在更新渲染时,useState
使用updateState
,它在内部调用 updateReducer
。它processes all updates in the queue .
最后,要在调用 setState
时触发渲染,将更新添加到队列后,它将元素安排为需要重新渲染的根元素。 Source
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
if (root !== null) {
const eventTime = requestEventTime();
scheduleUpdateOnFiber(root, fiber, lane, eventTime);
entangleTransitionUpdate(root, queue, lane);
}
在大多数情况下,类和功能组件最终会在这里做同样的事情。
然而,他们对这些事情中的每一个都使用单独的实现,从而导致细微的差异。
对于类组件,你的状态总是会在它调用类的 render
方法之前得到更新。
对于带有钩子(Hook)的函数组件,状态更新在每个钩子(Hook)被调用时发生。
虽然这显然是一种不同的方法,但这种差异并没有太多实际意义。在这两种情况下,状态更新都会及时发生。
关于reactjs - useState hook 如何能够重新渲染其父函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55262865/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!