提供者模式

提供者模式

使数据可用于多个组件。

在这篇文章中,因为我认为最好的学习方式是写作和分享。 模式.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 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/33054/04441308

posted @   哈哈哈来了啊啊啊  阅读(219)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示