为什么将 React Context 提供程序逻辑提取到自定义提供程序可以避免不必要的重新渲染?

问题描述 投票:0回答:1

以下代码片段的问题是,每当单击更改按钮时,组件

A
B
都会被重新渲染,而我只希望组件
C
被重新渲染,因为它是唯一一个消耗上下文的:

const UserContext = React.createContext({user: {name: 'name1'}, change: () => null})
const useUserContext = () => React.useContext(UserContext)

const A = () => {
    console.log('rendering A')
    return <B/>
}
const B = () => {
    console.log('rendering B')
    return <C/>
}

const C = () => {
    const user = useUserContext()
    console.log('rendering C', user)

    return (
        <div>
            <div>UserName:{user.user.name}</div>
            <button onClick={user.change}>Change</button>
        </div>
    )
}

const App = () => {
    const [user, setUser] = React.useState({name: 'name2'})

    const change = () => {
        console.log('changing name')
        setUser({name: 'name3'})
    }

    return (
        <div>
            <UserContext.Provider value={{user, change}}>
                <A/>
            </UserContext.Provider>
        </div>
    )
}

我通过将提供程序逻辑提取到自定义提供程序来完全缓解了该问题:

const UserContext = React.createContext({user: {name: 'name1'}, change: () => null})
const useUserContext = () => React.useContext(UserContext)

const UserProvider = ({children}) => {
    const [user, setUser] = React.useState({name: 'name2'})

    const change = () => {
        console.log('changing name')
        setUser({name: 'name3'})
    }

    return (
        <UserContext.Provider value={{user, change}}>
            {children}
        </UserContext.Provider>
    )
}

const A = () => {
    console.log('rendering A')
    return <B/>
}
const B = () => {
    console.log('rendering B')
    return <C/>
}

const C = () => {
    const user = useUserContext()
    console.log('rendering C', user)

    return (
        <div>
            <div>UserName:{user.user.name}</div>
            <button onClick={user.change}>Change</button>
        </div>
    )
}

const App = () => {
    return (
        <div>
            <UserProvider>
                <A/>
            </UserProvider>
        </div>
    )
}

但是,我不明白为什么这会对 React 产生任何影响?有人可以解释一下这两种情况的幕后发生了什么吗?

javascript reactjs react-context
1个回答
0
投票

JSX
编译为
React.createElement(...)
并返回一个对象。差异算法会在每次渲染时比较该对象。如果
UserProvider
接受
children
prop 作为组件实例(来自
createElement
的对象),则即使
UserProvider
重新渲染,该对象也不会更改其引用,因为它不是在
UserProvider
内部创建,而是在其父级中创建。

  • 当组件类型与之前的不同时,就会发生渲染 渲染。
  • 组件实例不同时会发生重新渲染 比之前的渲染。

在第一个示例中,每次渲染都会调用

React.createElement(A)
。在你的第二个例子中 - 仅在
App

中出现一次
© www.soinside.com 2019 - 2024. All rights reserved.