creamidea / creamidea.github.com

冰糖火箭筒&&蜂蜜甜甜圈
https://creamidea.github.io/
4 stars 4 forks source link

React Array 检查 Key 原理 #45

Open creamidea opened 2 years ago

creamidea commented 2 years ago

问题描述

有如下代码,静态编写多子组件,不会出现 key 警告

export function App({ name }) {
    return (
        <div>
            <h1>{name}</h1>
            <h1>{name}</h1>
            <h1>{name}</h1>
        </div>
    )
}

但是,如果使用动态的形式创建多个子组件,就会出现 key 警告

export function App({ name }) {
    return (
        <div>
            {
                [1,2,3].map(id => {
                    return <h2>{id}</h2>
                })
            }
        </div>
    )
}

原理探索

在新版 JSX 解析的过程中,开启如下配置

image

那么在分析 JSX 代码的时候,对于静态多个子组件,会对其父组件使用 jsxs。而对于动态版本,则会使用 jsx

image

jsxsjsx 函数定义在文件 packages/react-reconciler/src/ReactChildFiber.new.js

image

通过第四个参数控制,如果为 true,则会进入 validateChildKeys -> validateExplicitKey 提前设置 element._store.validated = true;。那么在 reconcileChildrenArray 阶段,warnForMissingKey 函数会在判断 !child._store || child._store.validated || child.key != null 提前返回(child._store.validated 为 true)

附 警告时调用堆栈

validateExplicitKey (index.js:formatted:2473)
validateChildKeys (index.js:formatted:2473)
jsxWithValidation (index.js:formatted:2473)  <- 这里调用时,第四个参数为 false
App (App5.js:6)
renderWithHooks (index.js:formatted:2473)
mountIndeterminateComponent (index.js:formatted:2473)
beginWork (index.js:formatted:2473)
beginWork$1 (index.js:formatted:2473)
performUnitOfWork (index.js:formatted:2473)
workLoopSync (index.js:formatted:2473)
renderRootSync (index.js:formatted:2473)
performSyncWorkOnRoot (index.js:formatted:2473)
scheduleUpdateOnFiber (index.js:formatted:2473)
updateContainer (index.js:formatted:2473)
(anonymous) (index.js:formatted:2473)
unbatchedUpdates (index.js:formatted:2473)
legacyRenderSubtreeIntoContainer (index.js:formatted:2473)
render (index.js:formatted:2473)
(anonymous) (index.js:10)
./src/index.js (index.js:24)
__webpack_require__ (bootstrap:856)
fn (bootstrap:150)
1 (reportWebVitals.js:14)
__webpack_require__ (bootstrap:856)
checkDeferredModules (bootstrap:45)
webpackJsonpCallback (bootstrap:32)
(anonymous) (main.chunk.js:1)
creamidea commented 2 years ago

https://github.com/reactjs/rfcs/pull/107