React 在组件间共享状态

在组件间共享状态

有时候,你希望两个组件的状态始终同步更改。要实现这一点,可以将相关 state 从这两个组件上移除,并把 state 放到它们的公共父级,再通过 props 将 state 传递给这两个组件。这被称为“状态提升”,这是编写 React 代码时常做的事。

学习内容

  • 如何使用状态提升在组件之间共享状态
  • 什么是受控组件和非受控组件

举例说明一下状态提升
在这个例子中,父组件 Accordion 渲染了 2 个独立的 Panel 组件。

  • Accordion
    • Panel
    • Panel

每个 Panel 组件都有一个布尔值 isActive,用于控制其内容是否可见。

import React, { useState } from 'react';
import {Button} from 'antd';// Accordion 父组件
const Accordion:React.FC=()=> {return (<><h2>我的旅游清单</h2><Panel title="未完成打卡地点"><ul><li>北京故宫</li><li>北京天安门</li><li>北京颐和园</li><li>北京王府井</li></ul></Panel><Panel title="已完成打卡地点"><ul><li>上海迪士尼</li><li>深圳世界之窗</li><li>广州"小蛮腰"</li><li>广州长隆</li></ul></Panel></>);
}
export default Accordion// 定义 Panel 组件的 props 类型
interface PanelProps {title: string;children: React.ReactNode;
}
// Panel 子组件
const Panel: React.FC<PanelProps>=({title,children})=> {const [isActive, setIsActive] = useState(false);return (<section style={{padding:"10px",background:"#e4e4e4",marginBottom:"10px"}}><h3>{title}</h3>{isActive ? (<p>{children}</p>) : (<Button variant="solid" color="primary" onClick={() => setIsActive(true)}>显示</Button>)}</section>);
}

在这里插入图片描述

请点击 2 个面板中的显示按钮:

在这里插入图片描述
我们发现点击其中一个面板中的按钮并不会影响另外一个,他们是独立的。
在这里插入图片描述
假设现在你想改变这种行为,以便在任何时候只展开一个面板。在这种设计下,展开第 2 个面板应会折叠第 1 个面板。你该如何做到这一点呢?“

要协调好这两个面板,我们需要分 3 步将状态“提升”到他们的父组件中。

  1. 从子组件中 移除 state 。
  2. 从父组件 传递 硬编码数据。
  3. 为共同的父组件添加 state ,并将其与事件处理函数一起向下传递。

这样,Accordion 组件就可以控制 2 个 Panel 组件,保证同一时间只能展开一个。

第 1 步: 从子组件中移除状态

你将把 Panel 组件对 isActive 的控制权交给他们的父组件。这意味着,父组件会将 isActive 作为 prop 传给子组件 Panel。我们先从 Panel 组件中 删除下面这一行:

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

然后,把 isActive 加入 Panel 组件的 props 中:

const Panel: React.FC<PanelProps> = ({ title, children, isActive}) => { 

现在 Panel 的父组件就可以通过 向下传递 prop 来 控制 isActive。但相反地,Panel 组件对 isActive 的值 没有控制权 —— 现在完全由父组件决定!

第 2 步: 从公共父组件传递硬编码数据

为了实现状态提升,必须定位到你想协调的 两个 子组件最近的公共父组件:

Accordion (最近的公共父组件)
Panel
Panel
在这个例子中,公共父组件是 Accordion。因为它位于两个面板之上,可以控制它们的 props,所以它将成为当前激活面板的“控制之源”。通过 Accordion 组件将硬编码值 isActive(例如 true )传递给两个面板:

import React from 'react';
import {Button} from 'antd';// Accordion 父组件
const Accordion:React.FC=()=> {return (<><h2>我的旅游清单</h2><Panel title="未完成打卡地点" isActive={true}><ul><li>北京故宫</li><li>北京天安门</li><li>北京颐和园</li><li>北京王府井</li></ul></Panel><Panel title="已完成打卡地点" isActive={false}><ul><li>上海迪士尼</li><li>深圳世界之窗</li><li>广州"小蛮腰"</li><li>广州长隆</li></ul></Panel></>);
}
export default Accordion// 定义 Panel 组件的 props 类型
interface PanelProps {title: string;children: React.ReactNode;isActive:boolean
}
// Panel 子组件
const Panel: React.FC<PanelProps>=({title,children,isActive})=> {return (<section style={{padding:"10px",background:"#e4e4e4",marginBottom:"10px"}}><h3>{title}</h3>{isActive ? (<p>{children}</p>) : (<Button variant="solid" color="primary">显示</Button>)}</section>);
}

在这里插入图片描述
你可以尝试修改 Accordion 组件中 isActive 的值,并在屏幕上查看结果。

第 3 步: 为公共父组件添加状态

状态提升通常会改变原状态的数据存储类型。

在这个例子中,一次只能激活一个面板。这意味着 Accordion 这个父组件需要记录 哪个 面板是被激活的面板。我们可以用数字作为当前被激活 Panel 的索引,而不是 boolean 值:

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

当 activeIndex 为 0 时,激活第一个面板,为 1 时,激活第二个面板。

在任意一个 Panel 中点击“显示”按钮都需要更改 Accordion 中的激活索引值。 Panel 中无法直接设置状态 activeIndex 的值,因为该状态是在 Accordion 组件内部定义的。 Accordion 组件需要 显式允许 Panel 组件通过 将事件处理程序作为 prop 向下传递 来更改其状态:

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

现在 Panel 组件中的 将使用 onShow 这个属性作为其点击事件的处理程序:

import React, { useState } from 'react';
import {Button} from 'antd';// Accordion 父组件
const Accordion: React.FC = () => {const [activeIndex, setActiveIndex] = useState(0);return (<div><h2 className="text-2xl font-bold mb-4">我的旅游清单</h2><Paneltitle="未完成打卡地点"isActive={activeIndex === 0}onShow={() => setActiveIndex(0)}><ul><li>北京故宫</li><li>北京天安门</li><li>北京颐和园</li><li>北京王府井</li></ul></Panel><Paneltitle="已完成打卡地点"isActive={activeIndex === 1}onShow={() => setActiveIndex(1)}><ul><li>上海迪士尼</li><li>深圳世界之窗</li><li>广州"小蛮腰"</li><li>广州长隆</li></ul></Panel></div>);
};export default Accordion;// 定义 Panel 组件的 props 类型
interface PanelProps {title: string;children: React.ReactNode;isActive: boolean;onShow: () => void;
}// Panel 子组件
const Panel: React.FC<PanelProps> = ({ title, children, isActive, onShow }) => {return (<section style={{padding:"10px",background:"#e4e4e4",marginBottom:"10px"}}><h3 className="text-xl font-bold mb-2">{title}</h3>{isActive ? (<p className="text-gray-700">{children}</p>) : (<Buttonvariant="solid"color="primary"onClick={onShow}>显示</Button>)}</section>);
};

在这里插入图片描述
点击下方显示按钮后
在这里插入图片描述
这样,我们就完成了对状态的提升!将状态移至公共父组件中可以让你更好的管理这两个面板。使用激活索引值代替之前的 是否显示 标识确保了一次只能激活一个面板。而通过向下传递事件处理函数可以让子组件修改父组件的状态。
在这里插入图片描述

每个状态都对应唯一的数据源

在 React 应用中,很多组件都有自己的状态。一些状态可能“活跃”在叶子组件(树形结构最底层的组件)附近,例如输入框。另一些状态可能在应用程序顶部“活动”。例如,客户端路由库也是通过将当前路由存储在 React 状态中,利用 props 将状态层层传递下去来实现的!

**对于每个独特的状态,都应该存在且只存在于一个指定的组件中作为 state。**这一原则也被称为拥有 “可信单一数据源”。它并不意味着所有状态都存在一个地方——对每个状态来说,都需要一个特定的组件来保存这些状态信息。你应该 将状态提升 到公共父级,或 将状态传递 到需要它的子级中,而不是在组件之间复制共享的状态。

你的应用会随着你的操作而变化。当你将状态上下移动时,你依然会想要确定每个状态在哪里“活跃”。这都是过程的一部分!

摘要

  • 当你想要整合两个组件时,将它们的 state 移动到共同的父组件中。
  • 然后在父组件中通过 props 把信息传递下去。
  • 最后,向下传递事件处理程序,以便子组件可以改变父组件的 state 。
  • 考虑该将组件视为“受控”(由 prop 驱动)或是“不受控”(由 state 驱动)是十分有益的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76888.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阶段性使用总结-通义灵码

序言 前段时间用通义灵码&#xff0c;参加了下数字中国闽江流域的比赛。https://www.dcic-china.com/competitions/10173 最后成绩一般般&#xff0c;106名&#xff0c;大概有2000多人参加这题目&#xff0c;估计有一堆小号。 按照下面这个思路建模的&#xff0c;迭代了大概15…

游戏引擎学习第228天

对上次的内容进行回顾&#xff0c;并为今天的开发环节做铺垫。 目前大部分功能我们已经完成了&#xff0c;唯一剩下的是一个我们知道存在但目前不会实际触发的 bug。这个 bug 的本质是在某些线程仍然访问一个已经被销毁的游戏模式&#xff08;mode&#xff09;之后的状态&…

游戏测试入门知识

高内聚指的是一个模块或组件内部的功能应该紧密相关。这意味着模块内的所有元素都应该致力于实现同一个目标或功能&#xff0c;并且该模块应当尽可能独立完成这一任务。 低耦合则是指不同模块之间的依赖程度较低&#xff0c;即一个模块的变化对其它模块造成的影响尽可能小。理…

L1-2 种钻石

题目 2019年10月29日&#xff0c;中央电视台专题报道&#xff0c;中国科学院在培育钻石领域&#xff0c;取得科技突破。科学家们用金刚石的籽晶片作为种子&#xff0c;利用甲烷气体在能量作用下形成碳的等离子体&#xff0c;慢慢地沉积到钻石种子上&#xff0c;一周“种”出了一…

基于开源技术生态的社群运营温度化策略研究——以“开源链动2+1模式AI智能名片S2B2C商城小程序源码”融合应用为例

摘要 在社交媒体与电商深度融合的背景下&#xff0c;社群运营的“温度化”成为企业构建用户忠诚度的核心命题。本文以康夏社群运营案例为切入点&#xff0c;结合“开源链动21模式AI智能名片S2B2C商城小程序源码”技术架构&#xff0c;分析其通过开源技术实现情感联结与商业价值…

编程技能:调试01,调试介绍

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;编程基础&#xff1a;位运算07&#xff0c;右移 回到目录 下一…

从零开始学A2A二 : A2A 协议的技术架构与实现

A2A 协议的技术架构与实现 学习目标 技术架构掌握 深入理解 A2A 协议的分层架构设计掌握各层次的功能和职责理解协议的工作原理和数据流 实现能力培养 能够搭建基本的 A2A 服务端掌握客户端开发方法实现智能体间的有效通信 架构设计理解 理解与 MCP 的本质区别掌握多智能体协…

UE5滚轮控制目标臂长度调整相机距离

UE5通过鼠标滚轮来控制摄像机目标臂长度 , 调整相机距离 看图就行,不多说,照着连就完事了

python的strip()函数用法; 字符串切片操作

python的strip()函数用法 目录 python的strip()函数用法代码整体功能概述代码详细解释1. `answer["output_text"]`2. `.strip()`3. `final_answer = ...`字符串切片操作:answer[start_index + len("Helpful Answer:"):].strip()整体功能概述代码详细解释1…

云服务模式全知道:IaaS、PaaS、SaaS与DaaS深度解析

云服务模式详解&#xff1a;IaaS、PaaS、SaaS与DaaS 在当今数字化快速发展的时代&#xff0c;云计算已经成为企业和开发者不可或缺的一部分。它提供了灵活的资源和服务&#xff0c;使得用户可以根据自己的需求选择最合适的解决方案。本文将详细介绍四种主要的云服务模式&#…

AIDL 语言简介

目录 软件包类型注释导入AIDL 的后端AIDL 语言大致上基于 Java 语言。AIDL 文件不仅定义了接口本身,还会定义这个接口中用到的数据类型和常量。 软件包 每个 AIDL 文件都以一个可选软件包开头,该软件包与各个后端中的软件包名称相对应。软件包声明如下所示: package my.pac…

PINN:用深度学习PyTorch求解微分方程

神经网络技术已在计算机视觉与自然语言处理等多个领域实现了突破性进展。然而在微分方程求解领域&#xff0c;传统神经网络因其依赖大规模标记数据集的特性而表现出明显局限性。物理信息神经网络(Physics-Informed Neural Networks, PINN)通过将物理定律直接整合到学习过程中&a…

程序化广告行业(89/89):广告创意审核的关键要点与实践应用

程序化广告行业&#xff08;89/89&#xff09;&#xff1a;广告创意审核的关键要点与实践应用 在程序化广告这个充满机遇与挑战的领域&#xff0c;持续学习和知识共享是我们不断进步的动力。一直以来&#xff0c;我都希望能和大家一同深入探索这个行业&#xff0c;今天让我们聚…

【ES6新特性】Proxy进阶实战

&#x1f31f;ES6 Proxy终极指南&#xff1a;从拦截器到响应式框架实现&#x1f525; 一、&#x1f4a1; 为什么Proxy是革命性的&#xff1f;先看痛点场景 1.1 Object.defineProperty的局限 &#x1f62b; // Vue2响应式实现 let data { count: 0 }; Object.defineProperty(…

c++解决动态规划

一、引言: 在我们学习了算法之后,我们一定遇到过贪心算法。而在贪心算法中就有着这样一个经典的例子——凑钱。 Eg: 你有面额为10、5、1的纸币,当你买菜时需要花费26元,请问需要最少的纸币张数是多少。 当我们用贪心算法去解决这个问题的时候,我们…

Qwen 2.5 VL 多种推理方案

Qwen 2.5 VL 多种推理方案 flyfish 单图推理 from modelscope import Qwen2_5_VLForConditionalGeneration, AutoTokenizer, AutoProcessor from qwen_vl_utils import process_vision_info import torchmodel_path "/media/model/Qwen/Qwen25-VL-7B-Instruct/"m…

机器视觉检测Pin针歪斜应用

在现代电子制造业中&#xff0c;Pin针&#xff08;插针&#xff09;是连接器、芯片插座、PCB板等元器件的关键部件。如果Pin针歪斜&#xff0c;可能导致接触不良、短路&#xff0c;甚至整机失效。传统的人工检测不仅效率低&#xff0c;还容易疲劳漏检。 MasterAlign 机器视觉对…

经典算法问题解析:两数之和与三数之和的Java实现

文章目录 1. 问题背景2. 两数之和&#xff08;Two Sum&#xff09;2.1 问题描述2.2 哈希表解法代码实现关键点解析复杂度对比 3. 三数之和&#xff08;3Sum&#xff09;3.1 问题描述3.2 排序双指针解法代码实现关键点解析复杂度分析 4. 对比总结5. 常见问题解答6. 扩展练习 1. …

1022 Digital Library

1022 Digital Library 分数 30 全屏浏览 切换布局 作者 CHEN, Yue 单位 浙江大学 A Digital Library contains millions of books, stored according to their titles, authors, key words of their abstracts, publishers, and published years. Each book is assigned an u…

地理人工智能中位置编码的综述:方法与应用

以下是对论文 《A Review of Location Encoding for GeoAI: Methods and Applications》 的大纲和摘要整理&#xff1a; A Review of Location Encoding for GeoAI: Methods and Applications 摘要&#xff08;Summary&#xff09; 本文系统综述了地理人工智能&#xff08;G…