提供者模式
提供者模式
使数据可用于多个组件。
在这篇文章中,因为我认为最好的学习方式是写作和分享。 模式.dev 我试图为您翻译这篇我觉得有用的文章。我选择不翻译整篇文章中的一些英文术语。祝你阅读愉快:)
在某些情况下,我们希望为应用程序中的许多(如果不是全部)组件提供数据。 道具
虽然我们可以使用 .
大多数时候, 支柱钻孔 我们遇到一种叫做;当我们将 props 传递到组件树的下方时,就会发生这种情况。依赖 props 重构代码几乎是不可能的,而且很难知道某些数据来自哪里。
假设您有一个包含某些数据的文件。 应用程序
我们有一个组件。在组件树的最下方,有一个列表,所有都需要这些数据。 项目清单
, 标题
ve 文本
我们有一个组件。要将这些数据传递给这些组件,我们需要通过多个组件层传递它。
在我们的代码库中,这看起来像这样:
函数应用程序(){
常量数据 = { ... } 返回 (
<div>
<SideBar data={data} />
<Content data={data} />
</div>
)
} 常量边栏 = ({ 数据 }) =><List data={data} />
常量列表 = ({ 数据 }) =><ListItem data={data} />
常量 ListItem = ({ date }) => <span>{data.listItem}</span> 常量内容 = ({ 数据 }) => (
<div>
<Header data={data} />
<Block data={data} />
</div>
)
常量头=({数据})=><div> {data.title}</div>
常量块 = ({ 数据 }) =><Text data={data} />
常量文本 = ({ 数据 }) =><h1> {数据.文本}</h1>
以这种方式转移道具可能会非常混乱。在将来 数据
如果我们要重命名 prop,我们需要在所有组件中重命名它。您的应用程序越大, 支柱钻孔 这可能很难。
如果我们可以跳过所有不需要使用此数据的组件层,那将是最佳选择。 数据
我们需要能够直接访问需要访问值的组件而不依赖道具钻孔的东西。
提供者模式 这就是它可以帮助我们的地方!使用提供者模式,我们可以为多个组件提供数据。我们可以将所有组件包装在 Provider 中,而不是通过 props 从每一层传递这些数据。 提供者
, 语境
它是对象提供给我们的高阶组件。 React 给了我们什么 创建上下文
我们可以使用该方法创建一个 Context 对象。
Provider 是一个包含我们要传输的数据的文件。 价值
得到探头。与此提供者一起包装 全部 成分, 价值
可以访问道具值。
const DataContext = React.createContext() 函数应用程序(){
常量数据 = { ... } 返回 (
<div>
<DataContext.Provider value={data}>
<SideBar />
<Content />
</DataContext.Provider>
</div>
)
}
现在 数据
我们不需要手动将 prop 传递给每个组件!好吧 项目清单
, 标题
ve 文本
成分 数据
我怎样才能获得它的价值?
她的组成部分, 使用上下文
使用钩子 数据
可以访问该值。在这种情况下,此挂钩是数据所在的位置 数据上下文
检索它所引用的上下文。 使用上下文
该钩子允许我们读取和写入数据到上下文对象。
const DataContext = React.createContext(); 函数应用程序(){
常量数据 = { ... } 返回 (
<div>
<SideBar />
<Content />
</div>
)
} 常量侧边栏 = () =><List />
常量列表 = () =><ListItem />
常量内容 = () =><div><Header /><Block /></div>
函数列表项(){
常量 { 数据 } = React.useContext(DataContext);
返回<span>{data.listItem}</span> ;
} 函数文本(){
常量 { 数据 } = React.useContext(DataContext);
返回<h1>{数据.文本}</h1> ;
} 函数头(){
常量 { 数据 } = React.useContext(DataContext);
返回<div>{data.title}</div> ;
}
数据
不以任何方式使用该值的组件 数据
无需担心价值。我们不再需要担心通过不需要 props 值的组件将 props 向下传递几个级别,这使得重构变得更加容易。
提供者模式对于共享全局数据非常有用。 Provider 模式的一个常见用例是将主题 UI 状态共享给许多组件。
假设我们有一个显示列表的简单应用程序。
本节中的代码。 密码箱 您可以通过访问
我们希望用户能够在亮模式和暗模式之间切换。当用户从深色模式切换到浅色模式(反之亦然)时,背景颜色和文本颜色应该会发生变化!而不是将当前主题值传递给每个组件, ThemeProvider 文件
我们可以包装它并将现有的主题颜色传递给提供者。
导出 const ThemeContext = React.createContext(); 常量主题 = {
光: {
背景:“#fff”,
颜色:“#000”
},
黑暗的: {
背景:“#171717”,
颜色:“#fff”
}
}; 导出默认函数 App() {
const [主题,setTheme] = useState("dark"); 功能切换主题(){
setTheme(主题===“光”?“黑暗”:“光”);
} 常量提供者值 = {
主题:主题[主题],
切换主题
}; 返回 (
<div className={`App theme-${theme}`}>
<ThemeContext.Provider value={providerValue}>
<Toggle />
<List />
</ThemeContext.Provider>
</div>
);
}
切换
ve 列表
两个组件 主题语境
由于它与提供程序一起包装,因此提供程序是一个 价值
传输为 主题
对其价值和 切换主题
我们可以访问 .
切换
在组件内部相应地更新主题 切换主题
我们可以使用该功能。
导入反应,{ useContext } 从“反应”;
从“./App”导入 { ThemeContext };
导出默认函数 Toggle() {
常量主题 = useContext(ThemeContext);
返回 (
<label className="switch">
<input type="checkbox" onClick={theme.toggleTheme} />
<span className="slider round" />
</label>
);
}
列表
组件本身并不关心主题的当前值。然而, 项目清单
制作组件!主题内容直接 项目清单
我们可以使用
导入反应,{ useContext } 从“反应”;
从“./App”导入 { ThemeContext };
导出默认函数 TextBox() {
常量主题 = useContext(ThemeContext);
返回<li style={theme.theme}>...</li> ;
}
本节中的代码。 密码箱 您可以通过访问
挂钩
我们可以创建一个钩子来为组件提供上下文。在每个组件中 使用上下文
而不是导入 Context ,我们可以使用一个返回我们需要的上下文的钩子。
函数 useThemeContext() {
常量主题 = useContext(ThemeContext);
返回主题;
}
确保它是一个有效的主题 使用上下文(主题上下文)
如果它返回一个错误的值,让我们抛出一个错误。
函数 useThemeContext() {
常量主题 = useContext(ThemeContext);
如果(!主题){
throw new Error("useThemeContext 必须在 ThemeProvider 中使用");
}
返回主题;
}
直接组件 ThemeContext.Provider
而不是用包装器包装组件来提供组件的值 HOC 我们可以创建(高阶组件)。通过这种方式,我们可以将上下文逻辑与渲染组件分离,这增加了提供者的可重用性。
功能 ThemeProvider({children}) {
const [主题,setTheme] = useState("dark");
功能切换主题(){
setTheme(主题===“光”?“黑暗”:“光”);
}
常量提供者值 = {
主题:主题[主题],
切换主题
};
返回 (
<ThemeContext.Provider value={providerValue}>
{孩子们}
</ThemeContext.Provider>
);
}
导出默认函数 App() {
返回 (
<div className={`App theme-${theme}`}>
<ThemeProvider>
<Toggle />
<List />
</ThemeProvider>
</div>
);
}
主题语境
现在需要访问的每个组件 使用主题上下文
可以使用钩子。
导出默认函数 TextBox() {
常量主题 = useThemeContext();
返回<li style={theme.theme}>...</li> ;
}
通过为不同的上下文创建钩子,很容易将提供者的逻辑与呈现数据的组件分开。
示例用法
一些库为我们可以在消费组件中使用的值提供内置的提供程序。一个很好的例子是 样式化组件 (样式化的组件)。
理解这个例子不需要任何样式组件的经验。
styled-components 库适合我们。 主题提供者
提供。每个 样式化组件 将能够访问此提供程序的值!我们可以使用提供给我们的内容,而不是自己创建上下文 API!
让我们使用相同的 List 示例并添加组件 样式化组件
从库导入 主题提供者
让我们把它包起来。
从“样式化组件”导入 { ThemeProvider };
导出默认函数 App() {
const [主题,setTheme] = useState("dark");
功能切换主题(){
setTheme(主题===“光”?“黑暗”:“光”);
}
返回 (
<div className={`App theme-${theme}`}>
<ThemeProvider theme={themes[theme]}>
<>
<Toggle toggleTheme={toggleTheme} />
<List />
</>
</ThemeProvider>
</div>
);
}
项目清单
组件的内联 风格
而不是转移探头, 风格化的.li
我们将制作组件。因为它是一个样式化的组件 主题
我们可以达到价值!
从“样式组件”导入样式;
导出默认函数 ListItem() {
返回 (
<Li>
拥有客户服务非常重要,但这就是它的方式
随着时间的推移,它们会伴随着巨大的劳动和痛苦而发生。至少对于
来吧,没有人应该练习任何类型的工作,除了其中的一些
祝你好运
</Li>
);
}
const Li = styled.li`
${({ 主题 }) => `
背景颜色:${theme.backgroundColor};
颜色:${theme.color};
`}
`;
现在真棒 主题提供者
我们可以轻松地将样式应用到我们所有使用 !
本节中的代码。 密码箱 您可以通过访问
优点
提供者模式/上下文 API 可以将数据传递给许多组件,而无需手动将它们传递到每个组件层。
它降低了重构代码时意外输入错误的风险。以前,如果我们想稍后重命名一个 prop,我们必须在使用该值的整个应用程序中重命名它。
现在可以看作是一种反模式 螺旋钻 我们不必处理它。以前,可能很难理解应用程序的数据流,因为某些 prop 值的来源并不总是很清楚。使用 Provider 模式,我们不再需要将 props 传递给不关心这些数据的组件。
使用 Provider 模式维护全局状态很容易,因为我们可以让组件访问全局状态。
缺点
在某些情况下,过度使用提供者模式会导致性能问题。在每个状态更改中使用此上下文的所有组件 重新渲染 已经完成了。
让我们看一个例子。 按钮
组件索引 增量
我们有一个简单的计数器,每次单击按钮时都会递增。而且 重置
在组件中,倒计时 0
回到 重置
我们有按钮。
然而 增量
单击 时,只能看到没有重新渲染的数字。 重置
组件中的日期也重做!
本节中的代码。 密码箱 您可以通过访问
重置
组件德 使用计数上下文
它被重新渲染,因为它被消耗了。在较小的应用程序中,这无关紧要。在较大的应用程序中,将频繁更新的值传递给许多组件可能会对性能产生负面影响。
为确保组件不会消耗具有可更新的不必要值的提供程序,您可以为每个单独的用例创建多个提供程序。
资源
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」