React笔记_组件之间进行数据传递

目录

父子组件传值- props

在React中父子组件传值是单向数据流 => 数据必须是由父级传到子级或者子级传递给父级层层传递!

父传子

父组件通过在子组件的JSX标签上添加属性的方式来传递数据,子组件通过 props 对象接收。

传递的数据类型是不受限制的 = > 可以是字符串、数字、数组、对象、函数、甚至JSX元素。

  • 父组件

    html 复制代码
      <son  子组件接收的属姓名=父组件的属性值></son>
    javascript 复制代码
    import  {useState} from 'react'
    import Funcom from '../component/Funcom'
    import Clcom from '../component/Clcom'
    
    export default function Page1(){
      const [num, setNum] = useState(1)
    
      return (
        <div>
          {/* 函数子组件 */}
          <Funcom num={num}/>
          {/* 类子组件 */}
          <Clcom num ={num}/>
          <button onClick={()=>{setNum(preNum=>preNum+1)}}>editNum</button>
        </div>
      )
    }
  • 子组件:

    • 函数子组件组件:在调用函数时将props作为参数传入;

      javascript 复制代码
      function FunSon(props){
      // props直接使用
      }
      javascript 复制代码
      export default function Fun(props){
       console.log('渲染了') // 无论有没有接收参数只要父组件更新都会重新渲染子组件
       return (
         <div>
           <h4>函数子组件==》{props.num}</h4>
         </div>
       )
      }
    • 类子组件:通过this获取props

      javascript 复制代码
      class ClaSon extends React.Component{
       // this.props使用
      }
      javascript 复制代码
      import React from 'react'
      
      export default  class Clcom extends React.Component {
        render() {
          console.log('render')  // 无论有没有接收参数只要父组件更新都会重新渲染子组件
          return (
          <>
           <h4>类组件==》{this.props.num}</h4>
          </>
          )
        }
      }
子传父

子组件不能直接修改父组件的状态(数据单向流动),果需要,父组件必须传递一个函数给子组件作为 prop,子组件在需要时调用这个函数,将数据作为参数传回给父组件。

  • 父组件

    html 复制代码
    <Son 子组件调用的方法名={父组件的方法}></Son>
  • 子组件

    javascript 复制代码
    // 当子组件想要修改父组件的数据时
    // val是要修改的值
     props.方法名(val) // 函数组件
     this. props.方法名(val) // 类组件
  • 举例说明
    父组件

    javascript 复制代码
    import  {useState} from 'react'
    import Funcom from '../component/Funcom'
    import Clcom from '../component/Clcom'
    
    export default function Page1(){
      const [num, setNum] = useState(1)
    
      function editNum(val){
        setNum(val)
      }
      return (
        <div>
          {/* 函数子组件 */}
          <Funcom num={num} editNum={editNum}/>
          {/* 类子组件 */}
          <Clcom num ={num}  editNum={editNum}/>
        </div>
      )
    }

    函数子组件

    javascript 复制代码
    export default function Fun(props){
      return (
        <div>
          <h4>函数子组件==》{props.num}</h4>
          <button onClick={()=>{props.editNum(props.num+2)}}>函数组件editNum</button>
        </div>
      )
    }

    类子组件

    javascript 复制代码
    import React from 'react'
    
    export default  class Clcom extends React.Component {
      render() {
        console.log('render')
        return (
        <>
         <h4>类组件==》{this.props.num}</h4>
         <button onClick={()=>{this.props.editNum(this.props.num+1)}}>类组件editNum</button>
        </>
        )
      }
    }

嵌套组件传值-Context API

概念

Context API 是 React 提供的一种组件间通信机制,允许数据在组件树中直接传递,无需通过 props 逐层传递。

React.createContext API

React.createContext 是一个函数,用于创建一个Context对象 => 该对象是管理 "全局"或"跨组件"数据的容器和通信机制。

javascript 复制代码
React.createContext(defaultValue)
  • 参数:defaultValue;

    当一个组件在树中找不到匹配的 Provider 时,React.Consumer/useContext就会返回这个 defaultValue;

    这个默认值对于测试组件或在没有提供 Provider 的情况下非常有用

  • 返回值:一个Context对象

    javascript 复制代码
    {
      $$typeof: Symbol(react.context), // React 内部用于识别类型的符号
      _currentValue: 'light',          // 内部保存的当前值
      Provider: { ... },               // Provider 组件
      Consumer: { ... },               // Consumer 组件 (已较少使用)
      displayName: undefined,          // 用于 React DevTools 显示的名称
    }
Provider组件

Provider组件是React.createContext函数返回对象的属性,允许消费组件订阅 Context 的变化。

html 复制代码
<MyContext.Provider value={...}>
 <!-- 子组件树-->
</MyContext.Provider>

value就是要传递给所有下层组件的数据,只要 value发生变化,所有订阅该 Context 的后代组件都会强制重新渲染,即使它们使用了 React.memo 或 shouldComponentUpdate。

正确示例
javascript 复制代码
  const ThemContext = createContext({theme:'right', color: 'red'})
  const [theme, setTheme] = useState({theme:'right', color: 'red'})

  return (
    <div>
      <ThemContext.Provider value={theme}>
          {/* 其中所有的子组件以及其子组件都可以获取到value */}
        <Funcom />
        <Clcom />
      </ThemContext.Provider>
      
    </div>
  )
错误示例
html 复制代码
<div>
  <ThemContext.Provider value={{theme:'right', color: 'red'}}>
    {/* 其中所有的子组件以及其子组件都可以获取到value */}
    <Funcom />
    <Clcom />
  </ThemContext.Provider>    
</div>

每次渲染时,value={ theme:'right', color: 'red' }都会创建一个全新的对象,导致所有消费者不必要的重渲染。

消费 Context

kan su me

React.Consumer组件

React.Consumer是类组件中订阅 Context 变更的方式,函数组件已经逐渐使用useContext这个hook来替代了。

子元素是一个函数,函数的参数就是 ThemeContext 的当前值,返回值就是需要渲染的vodm;

html 复制代码
 <ThemeContext.Consumer>
 {value=>{
   vdom
   }
 }
 </ThemeContext.Consumer>

举例说明

  • 将context提取为一个单独的文件themeContext

    javascript 复制代码
    import  {createContext} from 'react'
    export default createContext({theme:'right', color: 'red'})
  • 在顶级组件引入

    javascript 复制代码
    import  {useState} from 'react'
    import Funcom from '../component/Funcom'
    import Clcom from '../component/Clcom'
    import ThemContext from '../utils/themeContext'
    export default function Page1(){
    
      const [theme, setTheme] = useState({theme:'right', color: 'red'})
      function editTheme(){
        setTheme(prevalue => ({...prevalue, theme: prevalue.theme=='right' ? 'dack' : 'right',}))
      }
      return (
        <div>
          <ThemContext.Provider value={theme}>
              {/* 其中所有的子组件以及其子组件都可以获取到value */}
            <Funcom />
            <Clcom />
            <button onClick={editTheme}>edittheme</button>
          </ThemContext.Provider>
        </div>
      )
    }
  • 子组件中若是不需要使用则完全不需要改变

  • 在想要使用的组件去消费,比如此处在孙组件使用

    javascript 复制代码
     import React from 'react'
     import  ThemeContext  from '../utils/themeContext'
     
     class SonFun2 extends React.Component{
       render(){
         console.log('孙组件')
         return(
           <ThemeContext.Consumer>{
             value=>(
               <>
                 <h4>今天的主题是:{value.theme}</h4>
                 <div>今天的颜色是:{value.color}</div>
               </>
             )
           }</ThemeContext.Consumer>
         )
       }
     }

    当在顶级组件点击按钮修改value值时会重新渲染所有组件,包括子组件(因为通过setState去修改数据本身就会渲染所有子组件)

useContext Hook

useContext是函数组件中订阅 Context 变更的方式

javascript 复制代码
const value = useContext(ThemeContext)

value就是要传递给所有下层组件的数据,只要 value发生变化,所有订阅该 Context 的后代组件都会强制重新渲染

举例说明

javascript 复制代码
function SonFun(){
  const value = useContext(ThemeContext)
  return (
    <div>
      <h4>function</h4>
      <h4>今天的主题是:{value.theme}</h4>
      <div>今天的颜色是:{value.color}</div>
    </div>
  )
}
区别
函数组件 类组件
方式 useContext API Context.consumer组件
语法 只需要在函数顶部调用hook ,简单明了 需要在组件jsx语法中嵌套一个函数,语法稍显冗长
易读性 可以并行调用多个context,简单易懂 若是存在多个context,容易造成回调地狱
性能 基本相同 基本相同
使用场景

推荐在值不经常改变的地方使用context,如主题切换用户信息认证管理一些全局的、许多组件都需要的数据

对于频繁更新的数据, 如表单输入、实时坐标等,Context 可能不是最优解,因为只要 Context 的 value 变化,所有消费该 Context 的组件都会重新渲染,即使它们只使用了 value 的一部分。

举例说明-用户信息

状态管理-Redux

redux

相关推荐
F2E_Zhangmo3 小时前
基于cornerstone3D的dicom影像浏览器 第二章 加载本地文件夹中的dicom文件并归档
前端·javascript·css
念念不忘 必有回响3 小时前
js设计模式-装饰器模式
javascript·设计模式·装饰器模式
weixin_584121433 小时前
vue3+ts导出PDF
javascript·vue.js·pdf
要做朋鱼燕4 小时前
【C++】 priority_queue 容器模拟实现解析
开发语言·c++·笔记·职场和发展
ST.J4 小时前
swing笔记
java·笔记
Zacks_xdc4 小时前
【前端】使用Vercel部署前端项目,api转发到后端服务器
运维·服务器·前端·安全·react.js
给月亮点灯|4 小时前
Vue基础知识-脚手架开发-使用Axios发送异步请求+代理服务器解决前后端分离项目的跨域问题
前端·javascript·vue.js
叫我阿柒啊4 小时前
从Java全栈到前端框架:一次真实的面试对话与技术解析
java·javascript·typescript·vue·springboot·react·前端开发
张迅之4 小时前
【React】Ant Design 5.x 实现tabs圆角及反圆角效果
前端·react.js·ant-design