GithubHelp home page GithubHelp logo

React Hooks 原理 about blog HOT 68 OPEN

brickspert avatar brickspert commented on May 15, 2024 132
React Hooks 原理

from blog.

Comments (68)

brickspert avatar brickspert commented on May 15, 2024 21

是否需要在setState函数中把cursor重置为0,在rerender的时候才能按照hook在组件函数内的书写顺序从0依次获取memoizedState中的值?

function setState(newState) {
  memoizedState[currentCursor] = newState;
  // reset
  cursor = 0;
  render();
}

例子中在 render() 里面把 cursor 置为 0 了。

from blog.

feibi avatar feibi commented on May 15, 2024 6

最开始有个疑问:为什么 useState 的 memoizedState 要是数组?如果是对象多好,这样就能一一对应上了,就可以突破 hooks 只能写在函数组件顶层的限制了。
看到最后,发现其实是个链表,并不是简单的数组呀。。。 所以我猜测为什么 memoizedState 不用 key value 这种方式存的原因是出于性能考虑吗?(也就是 key value 形式的数据结构 并没有 链表 形式的快)

最近面试遇到这个问题,大致了解了一下,链表是在内存里申请了一块连续的空间,而map是随机分散存储的,所以链表的查询会更快一些,一般大佬们的程序都会考虑要结合硬件层面来设计的

链表是动态分配内存,是非连续的。数组才是连续的,且是静态分配的

from blog.

wbcs avatar wbcs commented on May 15, 2024 5

还是无法理解: “Capture Value” 特性是如何产生的

每次rerender都会重新执行一遍函数组件本身, 每次执行都会是全新的context,capture只是闭包保存对应的context,所以后续更新 不会影响之前的context,那之前闭包捕获的context也就不会变了。

from blog.

liang520 avatar liang520 commented on May 15, 2024 4

为什么 state声明在外面,点击的时候,view才变化,没想明白 @brickspert

from blog.

rtxu avatar rtxu commented on May 15, 2024 2

赞,会用与会实现,理解的深度就是不一样

from blog.

zhangbin625 avatar zhangbin625 commented on May 15, 2024 2

大神 有一点想请教一下
function useState(initialValue) {
memoizedState[cursor] = memoizedState[cursor] || initialValue;
const currentCursor = cursor;
function setState(newState) {
memoizedState[currentCursor] = newState;
render();
}
return [memoizedState[cursor++], setState]; // 返回当前 state,并把 cursor 加 1
}
对于memoizedState[cursor] = memoizedState[cursor] || initialValue;这么实现的话 是不是如果setState(null)或者是setState(undefind)是不是 state都会被付成默认值了

from blog.

gaoxianglyx avatar gaoxianglyx commented on May 15, 2024 2

image
这个事件触发的时候应该下标应该是 1 吧

为什么是 1 呢?每次都是从 0 开始重新执行的。可以在这个例子中试试呢:
https://codesandbox.io/s/50ww35vkzl

这里从0开始,是指render都会从0开始执行hook。但是对于setUsername('fan hello')这个setState方法来说,cursor应该是1。
这是我个人的理解,这个图上标注似乎会引起一点歧义,如果不对请指正

from blog.

glud123 avatar glud123 commented on May 15, 2024 2

image
这个事件触发的时候应该下标应该是 1 吧

为什么是 1 呢?每次都是从 0 开始重新执行的。可以在这个例子中试试呢:
https://codesandbox.io/s/50ww35vkzl

这里从0开始,是指render都会从0开始执行hook。但是对于setUsername('fan hello')这个setState方法来说,cursor应该是1。
这是我个人的理解,这个图上标注似乎会引起一点歧义,如果不对请指正

第一句描述的没有异议,第二句中的 "cursor 应该是 1" 这句存在歧义,我们可以观察一下 setState 方法执行过程,发现其中维护memoizedState 数组下标的变量是 useState 方法中定义的 currentCursor 变量而不是 cursor,实际上 currentCursor 的值才是1。变量 cursor 的值在执行setState 中 render 方法之前是 memoizedState 数组的长度(即所存储hooks的数量,因为 useState 和 useEffect 中最后都执行了cursor++ 操作),在执行setState 中 render方法之后才会重置为 0。
图中描述的是变量 cursor 值的变化,所以作者描述的没什么问题,如果加上 currentCursor 值得变化大家可能就更容易理解了。

from blog.

brickspert avatar brickspert commented on May 15, 2024 1

请问,这个useState在多个组件中引入,彼此之间会不会有影响(全局只有一个memoizedState )?

这个例子里面会。因为共用了一个 memoizedState。
但是在 React 中,是把数据存在 fiber node 上的。也就是,每个组件都有自己的 memoizedState.

from blog.

brickspert avatar brickspert commented on May 15, 2024 1

棒! _state = _state | initialValue 应该是 _state = _state || initialValue

感谢~,已修正。

from blog.

brickspert avatar brickspert commented on May 15, 2024

@liang520 如果放在 useState 里面,是不是重新渲染每次都会重新调用 useState 重置掉?

from blog.

liang520 avatar liang520 commented on May 15, 2024

@brickspert 看明白了

from blog.

ChinDer avatar ChinDer commented on May 15, 2024

memoizedState => memorizedState

from blog.

KayneWang avatar KayneWang commented on May 15, 2024

砖家写的文章依旧简单明了~

from blog.

masterx0 avatar masterx0 commented on May 15, 2024

很清晰明了了

from blog.

watsonnnnn avatar watsonnnnn commented on May 15, 2024

除了用变量存state还有别的吗

from blog.

BurnhamZhang avatar BurnhamZhang commented on May 15, 2024

当我以为我会用hook的时候 useEffect 内的 setInterval 把我打蒙了,闭包是啥时候出现的都没看懂

from blog.

yushengling avatar yushengling commented on May 15, 2024

一直关注,一直学习,感谢你的陪伴,可以借鉴学习React Hooks 入门教程http://www.ruanyifeng.com/blog/2019/09/react-hooks.html

from blog.

kakeiChen avatar kakeiChen commented on May 15, 2024

follow

from blog.

JuneScut avatar JuneScut commented on May 15, 2024

为什么 state声明在外面,点击的时候,view才变化,没想明白 @brickspert

不然的话state只是一个useState函数里边的局部变量,每次执行都会重新初始化为0呀

from blog.

AfterThreeYears avatar AfterThreeYears commented on May 15, 2024

是否需要在setState函数中把cursor重置为0,在rerender的时候才能按照hook在组件函数内的书写顺序从0依次获取memoizedState中的值?

function setState(newState) {
  memoizedState[currentCursor] = newState;
  // reset
  cursor = 0;
  render();
}

from blog.

chnliquan avatar chnliquan commented on May 15, 2024

image
这个事件触发的时候应该下标应该是 1 吧

from blog.

BigKongfuPanda avatar BigKongfuPanda commented on May 15, 2024

image
这个事件触发的时候应该下标应该是 1 吧

我也觉得此时的cursor不应该为0,为1的是currentCursor 这个局部变量,用来获取userName这个state在数组中的位置

from blog.

FrancisShi avatar FrancisShi commented on May 15, 2024

image
这个事件触发的时候应该下标应该是 1 吧

我也觉得此时的cursor不应该为0,为1的是currentCursor 这个局部变量,用来获取userName这个state在数组中的位置

同意。随处可见的闭包啊~

from blog.

brickspert avatar brickspert commented on May 15, 2024

image
这个事件触发的时候应该下标应该是 1 吧

为什么是 1 呢?每次都是从 0 开始重新执行的。可以在这个例子中试试呢:
https://codesandbox.io/s/50ww35vkzl

from blog.

lddlww avatar lddlww commented on May 15, 2024

请问,这个useState在多个组件中引入,彼此之间会不会有影响(全局只有一个memoizedState )?

from blog.

lddlww avatar lddlww commented on May 15, 2024

@brickspert 多谢多谢

from blog.

lhz960904 avatar lhz960904 commented on May 15, 2024

棒! _state = _state | initialValue 应该是 _state = _state || initialValue

from blog.

chnliquan avatar chnliquan commented on May 15, 2024

image
这个事件触发的时候应该下标应该是 1 吧

为什么是 1 呢?每次都是从 0 开始重新执行的。可以在这个例子中试试呢:
https://codesandbox.io/s/50ww35vkzl

我看你代码是 render 的时候才修改 cursor 为 0 吧,事件触发的时候,当时的 currentCursor 是 1,这时就会改变 memorizState[1] 的值

from blog.

wanghsinche avatar wanghsinche commented on May 15, 2024
memoizedState,cursor 是存在哪里的?如何和每个函数组件一一对应的?

我们知道,react 会生成一棵组件树(或Fiber 单链表),树中每个节点对应了一个组件,hooks 的数据就作为组件的一个信息,存储在这些节点上,伴随组件一起出生,一起死亡。

这句话我不能理解,博主能引用源代码来证明么?
就我理解,函数式组件既然已经是stateless,就不会有所谓出生,死亡等生命周期了。我更倾向于react的hook信息,即整个hook的链表是一个全局变量。

from blog.

wanghsinche avatar wanghsinche commented on May 15, 2024
memoizedState,cursor 是存在哪里的?如何和每个函数组件一一对应的?

我们知道,react 会生成一棵组件树(或Fiber 单链表),树中每个节点对应了一个组件,hooks 的数据就作为组件的一个信息,存储在这些节点上,伴随组件一起出生,一起死亡。

这句话我不能理解,博主能引用源代码来证明么?
就我理解,函数式组件既然已经是stateless,就不会有所谓出生,死亡等生命周期了。我更倾向于react的hook信息,即整个hook的链表是一个全局变量。

收回我的猜想。全局的hook无法实现条件渲染,应该是每个组件对应各自的hook。

from blog.

FounderIsShadowWalker avatar FounderIsShadowWalker commented on May 15, 2024

还是无法理解: “Capture Value” 特性是如何产生的

from blog.

FounderIsShadowWalker avatar FounderIsShadowWalker commented on May 15, 2024

理解了, 每次render 就是一个闭包, 会缓存住当前的所有状态, react class 是直接更新this.props的指向, 且没有闭包的概念, 所以全变了

from blog.

biliydog avatar biliydog commented on May 15, 2024

在demo3中,没有调用诸如useState或者this.setState之类的方法,那react是如何知道并且触发更新的呢?

from blog.

biliydog avatar biliydog commented on May 15, 2024

在demo3中,没有调用诸如useState或者this.setState之类的方法,那react是如何知道并且触发更新的呢?

抱歉,忽略了里面的render方法

from blog.

venoral avatar venoral commented on May 15, 2024
function setState(newState) {
    memoizedState[currentCursor] = newState;
    cursor = currentCursor; //是不是少了这一句??
    render();
  }

from blog.

GiambiHuang avatar GiambiHuang commented on May 15, 2024
function setState(newState) {
    memoizedState[currentCursor] = newState;
    cursor = currentCursor; //是不是少了这一句??
    render();
  }

不需要吧
下一步render()就會把cursor = 0
並且再次依照順序調用所有函數組件

from blog.

aaronlam avatar aaronlam commented on May 15, 2024

大神 有一点想请教一下
function useState(initialValue) {
memoizedState[cursor] = memoizedState[cursor] || initialValue;
const currentCursor = cursor;
function setState(newState) {
memoizedState[currentCursor] = newState;
render();
}
return [memoizedState[cursor++], setState]; // 返回当前 state,并把 cursor 加 1
}
对于memoizedState[cursor] = memoizedState[cursor] || initialValue;这么实现的话 是不是如果setState(null)或者是setState(undefind)是不是 state都会被付成默认值了

我也是有这么个疑问,如果值本身就是false的话,怎么办?

from blog.

brickspert avatar brickspert commented on May 15, 2024

大神 有一点想请教一下
function useState(initialValue) {
memoizedState[cursor] = memoizedState[cursor] || initialValue;
const currentCursor = cursor;
function setState(newState) {
memoizedState[currentCursor] = newState;
render();
}
return [memoizedState[cursor++], setState]; // 返回当前 state,并把 cursor 加 1
}
对于memoizedState[cursor] = memoizedState[cursor] || initialValue;这么实现的话 是不是如果setState(null)或者是setState(undefind)是不是 state都会被付成默认值了

确实会有这个问题。
这个文章只是一个示例 demo,不是百分百严谨。

from blog.

aaronlam avatar aaronlam commented on May 15, 2024

大神 有一点想请教一下
function useState(initialValue) {
memoizedState[cursor] = memoizedState[cursor] || initialValue;
const currentCursor = cursor;
function setState(newState) {
memoizedState[currentCursor] = newState;
render();
}
return [memoizedState[cursor++], setState]; // 返回当前 state,并把 cursor 加 1
}
对于memoizedState[cursor] = memoizedState[cursor] || initialValue;这么实现的话 是不是如果setState(null)或者是setState(undefind)是不是 state都会被付成默认值了

确实会有这个问题。
这个文章只是一个示例 demo,不是百分百严谨。

明白啦!还是感谢作者带来质量那么高的文章。

from blog.

thinkerHope avatar thinkerHope commented on May 15, 2024

看了好久那里没想明白cursor怎么重置为0的,看了demo才知道,哭了。

from blog.

EarthShakers avatar EarthShakers commented on May 15, 2024

🧱家就是强 通俗易懂 顺便问个问题 React为何要使用链表串联多个hook 相比数组的优势是什么呢?

from blog.

aaronlam avatar aaronlam commented on May 15, 2024

🧱家就是强 通俗易懂 顺便问个问题 React为何要使用链表串联多个hook 相比数组的优势是什么呢?

感觉链表的灵活性会比数组来的高吧?

from blog.

glud123 avatar glud123 commented on May 15, 2024

🧱家就是强 通俗易懂 顺便问个问题 React为何要使用链表串联多个hook 相比数组的优势是什么呢?

数组存储区间需要连续的内存,链表是则是非连续、非顺序的存储结构

from blog.

lx70770 avatar lx70770 commented on May 15, 2024

不懂就问,render函数怎么来的,是如何触发函数组件跟新的呢?

from blog.

acmu avatar acmu commented on May 15, 2024

不懂就问,render函数怎么来的,是如何触发函数组件跟新的呢?

看 demo 代码,有定义 render 函数

from blog.

acmu avatar acmu commented on May 15, 2024

最开始有个疑问:为什么 useState 的 memoizedState 要是数组?如果是对象多好,这样就能一一对应上了,就可以突破 hooks 只能写在函数组件顶层的限制了。

看到最后,发现其实是个链表,并不是简单的数组呀。。。 所以我猜测为什么 memoizedState 不用 key value 这种方式存的原因是出于性能考虑吗?(也就是 key value 形式的数据结构 并没有 链表 形式的快)

from blog.

acmu avatar acmu commented on May 15, 2024

还有建议:给 useState 里的 render() 那块加个注释,我刚开始看这块的时候,也比较懵

from blog.

lx70770 avatar lx70770 commented on May 15, 2024

最开始有个疑问:为什么 useState 的 memoizedState 要是数组?如果是对象多好,这样就能一一对应上了,就可以突破 hooks 只能写在函数组件顶层的限制了。

看到最后,发现其实是个链表,并不是简单的数组呀。。。 所以我猜测为什么 memoizedState 不用 key value 这种方式存的原因是出于性能考虑吗?(也就是 key value 形式的数据结构 并没有 链表 形式的快)

最近面试遇到这个问题,大致了解了一下,链表是在内存里申请了一块连续的空间,而map是随机分散存储的,所以链表的查询会更快一些,一般大佬们的程序都会考虑要结合硬件层面来设计的

from blog.

BoBoooooo avatar BoBoooooo commented on May 15, 2024

受教了

from blog.

aaronlam avatar aaronlam commented on May 15, 2024

最开始有个疑问:为什么 useState 的 memoizedState 要是数组?如果是对象多好,这样就能一一对应上了,就可以突破 hooks 只能写在函数组件顶层的限制了。
看到最后,发现其实是个链表,并不是简单的数组呀。。。 所以我猜测为什么 memoizedState 不用 key value 这种方式存的原因是出于性能考虑吗?(也就是 key value 形式的数据结构 并没有 链表 形式的快)

最近面试遇到这个问题,大致了解了一下,链表是在内存里申请了一块连续的空间,而map是随机分散存储的,所以链表的查询会更快一些,一般大佬们的程序都会考虑要结合硬件层面来设计的

链表是动态分配内存,是非连续的。数组才是连续的,且是静态分配的

貌似JS底层的数组也有分快数组和慢数组,慢数组用的是hash表来管理数组,也就是说其数组的内存应该不是连续的?

from blog.

Lanchouchou avatar Lanchouchou commented on May 15, 2024

最开始有个疑问:为什么 useState 的 memoizedState 要是数组?如果是对象多好,这样就能一一对应上了,就可以突破 hooks 只能写在函数组件顶层的限制了。
看到最后,发现其实是个链表,并不是简单的数组呀。。。 所以我猜测为什么 memoizedState 不用 key value 这种方式存的原因是出于性能考虑吗?(也就是 key value 形式的数据结构 并没有 链表 形式的快)

最近面试遇到这个问题,大致了解了一下,链表是在内存里申请了一块连续的空间,而map是随机分散存储的,所以链表的查询会更快一些,一般大佬们的程序都会考虑要结合硬件层面来设计的

链表是动态分配内存,是非连续的。数组才是连续的,且是静态分配的

应该是使用key value 会有key冲突的问题需要解决吧

from blog.

zhoucumt avatar zhoucumt commented on May 15, 2024

···
let _deps; // _deps 记录 useEffect 上一次的 依赖

function useEffect(callback, depArray) {
const hasNoDeps = !depArray; // 如果 dependencies 不存在
const hasChangedDeps = _deps
? !depArray.every((el, i) => el === _deps[i]) // 两次的 dependencies 是否完全相等
: true;
/* 如果 dependencies 不存在,或者 dependencies 有变化*/
if (hasNoDeps || hasChangedDeps) {
callback();
_deps = depArray;
}
}
···
depArray为空数组的时候,const hasNoDeps = !depArray;的值不一直是true,那么每次都callback都会执行吗?

from blog.

aaronlam avatar aaronlam commented on May 15, 2024

···
let _deps; // _deps 记录 useEffect 上一次的 依赖

function useEffect(callback, depArray) {
const hasNoDeps = !depArray; // 如果 dependencies 不存在
const hasChangedDeps = _deps
? !depArray.every((el, i) => el === _deps[i]) // 两次的 dependencies 是否完全相等
: true;
/* 如果 dependencies 不存在,或者 dependencies 有变化*/
if (hasNoDeps || hasChangedDeps) {
callback();
_deps = depArray;
}
}
···
depArray为空数组的时候,const hasNoDeps = !depArray;的值不一直是true,那么每次都callback都会执行吗?

空数组的话,!depArray 应该是 false 呀。

from blog.

cll123456 avatar cll123456 commented on May 15, 2024

厉害,学习了

from blog.

pfan8 avatar pfan8 commented on May 15, 2024

佩服!看了很多个讲解 hooks 原理的,讲得这么清晰易懂的就是🧱家这

from blog.

xianyulli avatar xianyulli commented on May 15, 2024

为什么 state声明在外面,点击的时候,view才变化,没想明白 @brickspert

写在里面函数每次执行都会重置

from blog.

MrLeihe avatar MrLeihe commented on May 15, 2024

···
let _deps; // _deps 记录 useEffect 上一次的 依赖
function useEffect(callback, depArray) {
const hasNoDeps = !depArray; // 如果 dependencies 不存在
const hasChangedDeps = _deps
? !depArray.every((el, i) => el === _deps[i]) // 两次的 dependencies 是否完全相等
: true;
/* 如果 dependencies 不存在,或者 dependencies 有变化*/
if (hasNoDeps || hasChangedDeps) {
callback();
_deps = depArray;
}
}
···
depArray为空数组的时候,const hasNoDeps = !depArray;的值不一直是true,那么每次都callback都会执行吗?

空数组的话,!depArray 应该是 false 呀。

就是要 false 呀

from blog.

wizardpisces avatar wizardpisces commented on May 15, 2024

全量 rerender 确实不会影响到 hooks 游标 index;
局部update如何确保index对应关系 (我理解这里只触发了部分hooks的,那游标是不是错乱了)?
还是在全量render的时候就跟vnode绑定,到更新的时候再动态重置游标?

更新(2021-10-15):

可能是实现上每个组件都绑定一个hooks数组,只需要在每个组件运行的时候维护一个独立游标即可,所以不存在全局的hookIndex紊乱问题

更新(2021-12-3):

依照上面的思路实现了一个简单版本的Hooks(可以局部更新)

from blog.

Cheering-baby avatar Cheering-baby commented on May 15, 2024

有毛病,如果我把state变成undefined,null,0, false这些的时候就会重置成initialState

from blog.

creampnx-x avatar creampnx-x commented on May 15, 2024

有毛病,如果我把state变成undefined,null,0, false这些的时候就会重置成initialState

确实 其实 useState() 在上下文中只有初始化hooks才会用吧,每一次初始化都是新的对象,state存在与否没有影响。

from blog.

wizardpisces avatar wizardpisces commented on May 15, 2024

有毛病,如果我把state变成undefined,null,0, false这些的时候就会重置成initialState

确实 其实 useState() 在上下文中只有初始化hooks才会用吧,每一次初始化都是新的对象,state存在与否没有影响。

没毛病,immutable模式

from blog.

unbro avatar unbro commented on May 15, 2024

一个组件内,react 是如何抓区和解析多个 useEffect 的

from blog.

wizardpisces avatar wizardpisces commented on May 15, 2024

一个组件内,react 是如何抓区和解析多个 useEffect 的

可以理解成每个组件内都会关联一个hooks队列

from blog.

unbro avatar unbro commented on May 15, 2024

一个组件内,react 是如何抓区和解析多个 useEffect 的

可以理解成每个组件内都会关联一个hooks队列

请问能讲下这块的工作原理吗

from blog.

wizardpisces avatar wizardpisces commented on May 15, 2024

unbro

楼主讲的算比较清楚了,具体实现可以看源码,啃不动的可以试试看这个简单的实现

from blog.

yueyueyaofaguang avatar yueyueyaofaguang commented on May 15, 2024

对这里不是很理解
Q:“Capture Value” 特性是如何产生的?
A:每一次 ReRender 的时候,都是重新去执行函数组件了,对于之前已经执行过的函数组件,并不会做任何操作。

困惑点在于:虽然每一次都会进行ReRender,但是如果都会从同一个memoizedState中取值的话,应该是能够获取到最新的值,不会存在“Capture Value” 特性

拜托大佬解惑~

from blog.

wozien avatar wozien commented on May 15, 2024

为什么 state声明在外面,点击的时候,view才变化,没想明白 @brickspert

因为每次重新render 的时候会重新执行 useState(0)呀,如果不放在外面的话,返回的state还是0

from blog.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.