Skip to main content

Render

re-render

Context

当 Context 变化时:

  • 未订阅当前 Context 的组件,不会触发 re-render
  • 若 context 为 Object, 除了变化的属性,订阅其他属性的组件,也会触发 re-render

考虑如下 Context,以及组件形式:

  • Context 包含 count, setCount, desc(不会变化的 string)
  • Body 订阅 count, setCount
  • Footer 订阅 desc
  • Body 出发 setCount 时,Body 和 Footer 会 re-render。其他组件,均不会 re-render。
import { FC, ReactNode, createContext, useState } from 'react';

const DESC = 'Click on the Vite and React logos to learn more';

export const AppContext = createContext<{
count: number;
setCount: (_: number) => void;
desc: string;
}>({
count: 0,
setCount: (count: number) => console.log(count),
desc: DESC,
});

interface AppContextProviderProps {
children?: ReactNode;
}

export const AppContextProvider: FC<AppContextProviderProps> = ({
children,
}) => {
const [count, setCount] = useState(0);

return (
<AppContext.Provider value={{ count, setCount, desc: DESC }}>
{children}
</AppContext.Provider>
);
};

Zustand

Zustand 提供了原子形式选择,来避免 state 中某个值变化,引起订阅了其他值的组件 re-render。

// useBearStore.ts
import { create } from 'zustand';
import { combine } from 'zustand/middleware';

const useBearStore = create(
combine(
{ count: 0, desc: 'Click on the Vite and React logos to learn more' },
set => ({
addCount: () => set(state => ({ count: state.count + 1 })),
}),
),
);

export default useBearStore;

// Body.tsx
const count = useBearStore(state => state.count);
const addCount = useBearStore(state => state.addCount);

// Footer.tsx
// addCount 时,不会 re-render
const desc = useBearStore(state => state.desc);
// addCount 时,会 re-render
const state = useBearStore();