跨组件渲染

ffy Lv3

为什么需要跨组件实时渲染?

在开发 React 应用时,我们经常遇到这样的场景:某个组件的状态变化需要即时反映在其他不相关的组件中。例如:

  • 用户在一个组件中编辑内容,其他组件需要立即看到更新
  • 多个组件需要共享同一份数据
  • 需要避免通过层层组件传递 props(即所谓的 prop drilling)

这种情况下,使用 React Context 来实现跨组件的实时渲染就显得尤为重要。

最小实现示例

以下是实现跨组件实时渲染的最简代码结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 1. 定义 Context 类型
interface SharedContextType {
data: any;
updateData: (newData: any) => void;
}

// 2. 创建 Context
const SharedContext = createContext<SharedContextType | undefined>(undefined);

// 3. 创建 Provider 组件
export function SharedProvider({ children }: { children: React.ReactNode }) {
const [data, setData] = useState<any>(null);

const updateData = useCallback((newData: any) => {
setData(newData);
}, []);

return (
<SharedContext.Provider value={{ data, updateData }}>
{children}
</SharedContext.Provider>
);
}

// 4. 创建自定义 Hook
export function useShared() {
const context = useContext(SharedContext);
if (!context) {
throw new Error('useShared must be used within SharedProvider');
}
return context;
}

实际应用分析

让我们以一个实际的 Mermaid 图表生成器项目为例,分析如何运用这个模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 1. 定义具体的数据结构
interface HistoryItem {
id: string;
content: string;
mermaidCode: string;
timestamp: number;
}

// 2. 实现带有持久化的 Context Provider
export function HistoryProvider({ children }: { children: React.ReactNode }) {
const [selectedHistory, setSelectedHistory] = useState<HistoryItem | null>(null);
const [historyList, setHistoryList] = useState<HistoryItem[]>([]);

// 数据持久化
useEffect(() => {
if (selectedHistory) {
localStorage.setItem('selectedHistory', JSON.stringify(selectedHistory));
}
}, [selectedHistory]);

// 实时更新方法
const addHistory = async (content: string, mermaidCode: string) => {
const historyItem: HistoryItem = {
id: Date.now().toString(),
content,
mermaidCode,
timestamp: Date.now()
};
setHistoryList(prev => [historyItem, ...prev]);
};

return (
<HistoryContext.Provider
value={{
selectedHistory,
setSelectedHistory,
addHistory,
historyList
}}
>
{children}
</HistoryContext.Provider>
);
}

在这个实际例子中,我们可以看到几个关键点:

  1. 状态定义:使用 TypeScript 接口明确定义了数据结构,确保类型安全
  2. 状态持久化:通过 useEffect 监听状态变化并保存到 localStorage
  3. 实时更新:通过 setHistoryList 确保状态更新后所有使用该 Context 的组件都能即时获得更新

当组件需要使用这些共享状态时,只需:

1
2
3
4
5
6
7
8
9
10
11
function HistoryViewer() {
const { selectedHistory } = useHistory();

return (
<div>
{selectedHistory && (
<div>{selectedHistory.content}</div>
)}
</div>
);
}

这种模式的优势在于:

  • 避免了 props 的层层传递
  • 实现了组件间的解耦
  • 确保了状态更新的实时性
  • 提供了类型安全的数据访问

参考资料

  • 标题: 跨组件渲染
  • 作者: ffy
  • 创建于 : 2025-02-16 15:40:06
  • 更新于 : 2025-05-10 10:23:35
  • 链接: https://ffy6511.github.io/2025/02/16/前后端/跨组件渲染/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论