REACT 在组件之间共享状态

devtools/2024/9/25 2:21:30/

有时,您希望两个组件的状态始终一起变化。要做到这一点,请从他们俩身上删除状态,将其移动到他们最近的共同父级,然后通过道具将其传递给他们。这被称为提升状态,这是编写 React 代码时最常见的事情之一。

举例提升状态

在此示例中,父组件呈现两个单独的 s:AccordionPanel

  • Accordion
    • Panel
    • Panel

每个组件都有一个布尔状态,用于确定其内容是否可见。PanelisActive

按两个面板的显示按钮:

import { useState } from 'react';function Panel({ title, children }) {const [isActive, setIsActive] = useState(false);return (<section className="panel"><h3>{title}</h3>{isActive ? (<p>{children}</p>) : (<button onClick={() => setIsActive(true)}>Show</button>)}</section>);
}export default function Accordion() {return (<><h2>Almaty, Kazakhstan</h2><Panel title="About">With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.</Panel><Panel title="Etymology">The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.</Panel></>);
}

请注意,按下一个面板的按钮不会影响另一个面板,因为它们是独立的。

该图显示了一个由三个组件组成的树,一个父组件标记为 Accordion,两个子组件标记为 Panel。两个 Panel 组件都包含值为 false 的 isActive。

最初,每个 的状态都是 ,所以它们看起来都折叠了PanelisActivefalse

与上一个图相同的图,突出显示了第一个子 Panel 组件的 isActive,表示单击时 isActive 值设置为 true。第二个 Panel 组件仍包含值 false。

单击任一按钮只会单独更新该状态PanelPanelisActive

但现在假设您要更改它,以便在任何给定时间仅展开一个面板。在这种设计下,展开第二个面板应该会折叠第一个面板。你会怎么做?

要协调这两个面板,您需要通过三个步骤将其状态“提升”到父组件:

  1. 从子组件中删除状态。
  2. 从公共父级传递硬编码数据。
  3. 将状态添加到公共父级,并将其与事件处理程序一起传递。

这将允许组件协调两个 s,并且一次只能展开一个。AccordionPanel

步骤 1:从子组件中删除状态

您将把 的控制权交给其父组件。这意味着父组件将作为 prop 传递。首先从组件中删除以下行PanelisActiveisActivePanelPanel

const [isActive, setIsActive] = useState(false);

取而代之的是,添加到道具列表中:isActivePanel

function Panel({ title, children, isActive }) {

现在,父组件可以通过将其作为 prop 传递来控制。相反,组件现在无法控制 - 现在由父组件决定!PanelisActivePanelisActive

步骤 2:从公共父级传递硬编码数据

若要提升状态,必须找到要协调的两个子组件中最接近的公共父组件:

  • Accordion (最接近的共同父级)
    • Panel
    • Panel

在此示例中,它是组件。由于它位于两个面板的上方,并且可以控制它们的道具,因此它将成为面板当前处于活动状态的“真相来源”。使组件将硬编码值(例如,)传递给两个面板:AccordionAccordionisActivetrue

import { useState } from 'react';export default function Accordion() {return (<><h2>Almaty, Kazakhstan</h2><Panel title="About" isActive={true}>With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.</Panel><Panel title="Etymology" isActive={true}>The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.</Panel></>);
}function Panel({ title, children, isActive }) {return (<section className="panel"><h3>{title}</h3>{isActive ? (<p>{children}</p>) : (<button onClick={() => setIsActive(true)}>Show</button>)}</section>);
}

 

尝试编辑组件中的硬编码值,并在屏幕上查看结果。isActiveAccordion

步骤 3:将状态添加到公共父级

提升状态通常会改变存储为状态的内容的性质。

在这种情况下,一次只能有一个面板处于活动状态。这意味着公共父组件需要跟踪哪个面板是活动面板。它可以不使用值,而是使用数字作为状态变量的活动索引:AccordionbooleanPanel

const [activeIndex, setActiveIndex] = useState(0);

当 是 时,第一个面板处于活动状态,当它处于活动状态时,它是第二个面板。activeIndex01

单击其中的“显示”按钮需要更改 中的活动索引。A 不能直接设置状态,因为它是在 .组件需要显式允许组件通过将事件处理程序作为 prop 向下传递来更改其状态:PanelAccordionPanelactiveIndexAccordionAccordionPanel

<>
<Panel
isActive={activeIndex === 0}
onShow={() => setActiveIndex(0)}
>
...
</Panel>
<Panel
isActive={activeIndex === 1}
onShow={() => setActiveIndex(1)}
>
...
</Panel>
</>

内部现在将使用道具作为其 click 事件处理程序:<button>PanelonShow

import { useState } from 'react';export default function Accordion() {const [activeIndex, setActiveIndex] = useState(0);return (<><h2>Almaty, Kazakhstan</h2><Paneltitle="About"isActive={activeIndex === 0}onShow={() => setActiveIndex(0)}>With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.</Panel><Paneltitle="Etymology"isActive={activeIndex === 1}onShow={() => setActiveIndex(1)}>The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.</Panel></>);
}function Panel({title,children,isActive,onShow
}) {return (<section className="panel"><h3>{title}</h3>{isActive ? (<p>{children}</p>) : (<button onClick={onShow}>Show</button>)}</section>);
}

这样就完成了提升状态!将状态移动到公共父组件中允许您协调两个面板。使用活动索引而不是两个“显示”标志可确保在给定时间只有一个面板处于活动状态。将事件处理程序传递给子级允许子级更改父级的状态。

每个州的单一事实来源

在 React 应用程序中,许多组件将有自己的状态。某些状态可能像输入一样“存在于”叶子组件(树底部的组件)附近。其他状态可能“生活”在更靠近应用程序顶部的位置。例如,即使是客户端路由库,通常也是通过将当前路由存储在 React 状态,并通过 props 传递来实现的!

对于每个唯一的状态,您将选择“拥有”它的组件。这一原则也被称为具有“单一事实来源”。这并不意味着所有状态都存在于一个地方,而是对于每个状态,都有一个特定的组件来保存该信息。与其在组件之间复制共享状态,不如将其提升到其共同的共享父级,并将其传递给需要它的子级。

你的应用会随着你的使用而改变。通常,当您仍在弄清楚状态的每个部分“居住”的位置时,您会向下或向上移动状态。这都是过程的一部分!


http://www.ppmy.cn/devtools/41019.html

相关文章

泰迪智能科技中职大数据实验室建设(职业院校大数据实验室建设指南)

职校大数据实验室是职校校园文化建设的重要部分&#xff0c;大数据实训室的建设方案应涵盖多个方面&#xff0c;包括硬件设施的配备、软件环境的搭建、课程资源的开发、师资力量的培养以及实践教学体系的完善等。 打造特色&#xff0c;对接生产 社会经济与产业的…

submitUpload() { this.$refs.upload.submit(); },

submitUpload() {this.$refs.upload.submit();}, submitUpload() 是一个函数&#xff0c;调用该函数会将 Vue 组件中的上传组件中的文件上传到服务器上。这个函数通过 this.$refs.upload.submit() 来实现&#xff0c;其中 this.$refs.upload 可以获取到上传组件的 DOM 对象&am…

[PythonWeb:Django框架]:前后端请求调用;

文章目录 接着上篇项目app包下面创建static包&#xff0c;引入jquery&#xff0c;bootstrap 相关js文件views.py编写apicompute文件夹下面的urls.py路由模块引入views.py刚刚定义的函数html发送ajax请求 接着上篇 https://blog.csdn.net/Abraxs/article/details/138739727?sp…

【Vue2】关于response返回数据的错误小记

关于Vue2中response返回数据的一个错误小记 如图&#xff0c;在这里返回的时候&#xff0c;后端是通过List< String >返回的&#xff0c;response接收到的实际上是一个Array数组&#xff0c;但是赋值给searchedTaskList的时候&#xff0c;需要在.then包括的范围里面赋值给…

Linux grpunconv命令教程:从阴影组转换回常规组(附实例详解和注意事项)

Linux grpunconv命令介绍 grpunconv命令用于将组从阴影组转换回常规组。这个命令创建了一个从组和一个可选的现有阴影组生成的组&#xff0c;然后移除阴影组。 Linux grpunconv命令适用的Linux版本 grpunconv命令在大多数Linux发行版中都可以使用&#xff0c;包括Debian、Ub…

matlab实现爬虫

在MATLAB中尝试实现一个基本的网络爬虫&#xff0c;以下是一个简单的示例&#xff0c;它使用 urlread 函数从网页上读取内容&#xff1a; % 网页的URL url https://example示例.com; % 使用urlread读取网页内容 % 注意&#xff1a;从R2019b开始&#xff0c;建议使用webr…

点击短信链接唤起Android App实战

一.概述 在很多业务场景中,需要点击短信链接跳转到App的指定页面。在Android系统中,想要实现这个功能,可以通过DeepLink或AppLink实现。二.方案 2.1 DeepLink 2.1.1 方案效果 DeepLink是Android系统最基础、最普遍、最广泛的外部唤起App的方式,不受系统版本限制。当用户…

android面试之LiveData的postValue和setValue的区别与使用

一般我们在连续多次调用postValue时会出现只有最后一个值通知观察者返回过来&#xff0c;也就是说多次调用postValue时&#xff0c;只有最后一次调用是有效的&#xff0c;而setValue时每一个值的变化都会通知到观察者&#xff0c;也就是说每一次调用都是有效的&#xff0c;那么…