React Hook如何保证每次渲染state不会丢失,Dva Model在state中存储数据的底层原理

问题描述

1、 我们知道JavaScript中想要实现类似于Java静态变量的话,可以用闭包和localStorage实现。
闭包:有权访问另一个函数作用域变量的函数叫做闭包。
满足三个条件

 1. 定义了局部变量
 2. 函数返回一个匿名函数
 3. 返回的匿名函数中需要使用第一步定义的局部变量

局部变量被另一个函数使用,即变量被引用,所以就不会被回收了,因此可以利用这一个特性来封装一个私有变量。

本地存储是一个window的属性,包括localStoragesessionStorage,前者一直存在,后者只是伴随着session,窗口关闭就会消失。
localStorage:存储数据就是直接给window.localStorage添加一个属性,它的读写删除等操作以键值对的方式存在。

2、 因为JavaScript中没有static这一说法,React中的Hook state就相当于是静态变量
在这里插入图片描述
①执行setN的时候会发生什么?n会发生什么变化?App()会重复执行吗?

n会改变,App会重复执行

②如果App()重复执行,useState(0)的时候,n的值会变化吗?

n每次的值会不一样,但是不是由setN改变的!

1、setN修改数据,并将更新后的数据存进state,覆盖原来的state
2、setN会触发<App />重复渲染(re-render)
3、useState会从更新后的state读取n的最新值
4、每个组件都拥有自己的state

useState调用顺序

若第一次渲染时n是第一个,m是第二个,k是第三个
则第二次渲染时必须保证顺序完全一致
所以React不允许出现如下代码

function App(){
    const [n, setN] = React.useState(0)
    let m, setM
    if(n % 2 === 1){
        /* error:
            * React Hook "React.useState" is called conditionally.
            * React Hooks must be called in the exact same order in every component render
            *原因: 因为useState内部原理是把state声明成一个数组,需要顺序一一对应,如上图
         */
        [m, setM] = React.useState(0)
    }
    return (
        <div className='App'>
            <p>{n}</p>
            <p>
                <button onClick={() => setN(n + 1)}>+1</button>
            </p>
            <p>{m}</p>
            <p>
                <button onClick={() => setM(m + 1)}>+1</button>
            </p>
        </div>
    )
}

hook如何保存数据
在react中通过currentRenderingFiber来标识当前渲染节点,每个组件都有一个对应的fiber节点,用来保存组件的相关数据信息。
每次函数组件渲染时,currentRenderingFiber就被赋值为当前组件对应的fiber,所以实际上hook是通过currentRenderingFiber来获取状态信息的。
currentRenderingFiber.memorizedState中保存一条hook对应数据的单向链表。

const hookNum = {
      memorizedState: null,
      next: hookName
}
hookName.next = hookAge;
currentRenderingFiber.memorizedState.next = hookNum;

当函数组件渲染时,每执行到一个hook,就会将currentRenderingFiber.memorizedState的指针向后移一下。这也是hook的调用顺序不能改变的原因(不能再条件语句中使用hook)

手写useState

let _state //全局_state用来存储state的值,避免重新渲染的时候被myUseState重置为初始值
const myUseState = initialValue => {
    _state = _state === undefined ? initialValue : _state
    const setState = (newValue) => {
        _state = newValue
        render()
    }
    return [_state, setState]
}

const render = () => {
    ReactDOM.render(<App1 />, document.getElementById('root'))
}

function App1(){
    const [n, setN] = myUseState(0)
    return (
        <div className='App'>
            <p>{n}</p>
            <p>
                <button onClick={() => setN(n + 1)}>+1</button>
            </p>
        </div>
    )
}

3、Dva的model如何存储数据?为什么可以跨页面使用?
Provider
Provider组件的任务是将stroe传递给子组件,它只是一个传递数据的组件,只需要将子组件展示出来就好。

本质上是个高阶组件,也是代理模式的一种实践方式。接收 redux 生成的 store 做参数后,通过上下文 context 将 store 传递进被代理组件。在保留原组件的功能不变的同时,增加了 store 的 dispatch 等方法。
(源自Dva官网)

在整个应用上包一层,使整个应用成为Provider的子组件
接收Redux的store作为props,通过context对象传递给子组件,所有的子组件都可以取得store
在这里插入图片描述

通过context传递属性的方式可以大量减少通过props 逐层传递属性的方式,可以减少组件之间的直接依赖关系。

  1. connect方法
    connect 也是一个代理模式实现的高阶组件,为被代理的组件实现了从 context 中获得 store 的方法。

connect 方法返回的也是一个 React 组件,通常称为容器组件。因为它是原始 UI 组件的容器,即在外面包了一层 State。
connect 方法传入的第一个参数是 mapStateToProps 函数,mapStateToProps 函数会返回一个对象,用于建立 State 到 Props 的映射关系。
(源自Dva官网)

被 connect 的 Component 会自动在 props 中拥有 dispatch 方法。

笔者似乎还是没有回答dva数据在底层到底是如何存储的,因为找了很多资料还是没有发现,且听后续分解……

Q&A
model底层state存储也是用闭包实现,那么这个东西写出来了,
model是怎么去使用的呢?

参考文档

[学习笔记]JS计数器,闭包和localStorage

React hooks的useState原理

【REACT HOOKS】useState是如何保存并更新数据的?

Dva源码解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值