当前位置: 首页 > news >正文

React组件间传值

文章目录

  • 1. 父子间传值
    • 1.1 使用props实现父子间传值
    • 1.2 使用ref实现父子间传值
  • 2. 状态提升
  • 3. 跨组件通信
  • 4. 状态提升案例:toDoList


1. 父子间传值

1.1 使用props实现父子间传值

概述:

  • 父传子:通过自定义属性向子组件传值,值可以是任何类型

  • 子传父:通过父组件把方法传给子组件,子组件调用传过去的方法完成传值

注意:

  1. 定义方法时尽可能的去使用箭头函数定义
  2. 调用方法时,尽可能的写小括号

使用:

父组件:

import React, { Component } from 'react'
import Child from './pages/Child'

class App extends Component {
  state = {
    num: 1
  }

  // 成员方法 箭头函数来定义,这样就没有this指向问题
  setNum = (n = 1) => this.setState(state => ({ num: state.num + n }))

  render() {
    let { num } = this.state
    return (
      <div>
        <Child num={num} setNum={this.setNum} />
      </div>
    )
  }
}

export default App

子组件:

import React, { Component } from 'react'

class Child extends Component {
  addNum = (evt, n = 1) => {
    n = n * 10
    this.props.setNum(n)
  }

  render() {
    let { num, setNum } = this.props
    return (
      <div>
        <h3>Child组件 -- {num}</h3>
        {/* 子去修改父传过来的数据,props它是单向数据流,子不能直接去修改 */}
        {/* 调用时,尽可能的写小括号 */}
        <button onClick={() => setNum(2)}>+++++</button>
        <button onClick={this.addNum}>+++++</button>
      </div>
    )
  }
}

export default Child

在这里插入图片描述

1.2 使用ref实现父子间传值

概述:

父组件利用 ref 对子组件做标记,通过调用子组件的方法以更改子组件的状态,也可以调用子组件的方法(说明:ref 获取当前组件对象,只针对的是使用类创建的组件才可以用此方案,类有实例,而函数没有实例,默认只针对于类组件)

使用:

父组件:

import React, { Component, createRef } from 'react'
import Child from './pages/Child'

class App extends Component {
  state = {
    title: '',
    msg: '父中的数据传给子' + Date.now()
  }

  childRef = createRef()

  render() {
    return (
      <div>
        {/* 
          父子间传值:通过ref引用对象完成对于【类组件】之间通信
          this.childRef.current 得到当前Child组件的实例对象
        */}
        <h3>{this.state.title}</h3>
        <hr />
        <Child ref={this.childRef} />
        <button
          onClick={() => {
            // 子中的数据在父中使用
            this.setState({
              title: this.childRef.current.state.title
            })
            // this.childRef.current.setState({ title: this.state.msg })
            this.childRef.current.setTitle(this.state.msg)
          }}
        >
          父组件中修改子组件中的数据
        </button>
      </div>
    )
  }
}

export default App

子组件:

import React, { Component } from 'react'

class Child extends Component {
  state = {
    title: '我是子组件'
  }

  setTitle = title => this.setState({ title })

  render() {
    return (
      <div>
        <h3>{this.state.title}</h3>
      </div>
    )
  }
}

export default Child

在这里插入图片描述

2. 状态提升

概述:

此方案用来解决兄弟组件间的传值问题,就是把共用的状态信息提升到父组件状态中。

在这里插入图片描述

使用:

import React, { Component } from 'react'

class Child1 extends Component {
  render() {
    let { setMsg } = this.props
    return (
      <div>
        Child1<input type="text" onChange={e => setMsg(e.target.value)} />
      </div>
    )
  }
}

class Child2 extends Component {
  render() {
    let { msg } = this.props
    return (
      <div>
        <h3>Child2 -- {msg}</h3>
      </div>
    )
  }
}

class App extends Component {
  state = {
    msg: ''
  }
  setMsg = msg => this.setState({ msg })

  render() {
    return (
      <div>
        <h1>App -- {this.state.msg}</h1>
        <Child1 setMsg={this.setMsg} />
        <Child2 msg={this.state.msg} />
      </div>
    )
  }
}

export default App

在这里插入图片描述

3. 跨组件通信

概述:

在 react 中没有类似 vue 中的事件总线来解决这个问题。在实际的项目中,当需要组件间跨级访问信息时,如果还使用组件层层传递 props,此时代码显得不那么优雅,甚至有些冗余。在 react 中,我们还可以使用 context 来实现跨级父子组件间的通信。

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据。

在React的 Context 中,数据我们可当成商品,发布数据的组件会用 provider 身份(卖方),接收数据的组件使用 consumer 身份(买方)

使用:

appContext(创建Context对象):

// context一个项目中可以有N个,但是一般情况下我们使用它,都是把它放在App组件中,一个项目一个
// context实现在跨组件通信,一般用于自定义组件所用
// context绑定消费是一定是一个对象

import { createContext } from 'react'

// Provider,Consumer 都是组件
// Provider 生产数据的组件
// Consumer 消费的组件

// 导出写法1
// const ctx = createContext()
// export const { Provider, Consumer } = ctx
// export default ctx


// 导出写法2
const ctx = createContext()
const { Provider, Consumer } = ctx
export {
  ctx as default,//默认导出
  Provider,//按需导出
  Consumer//按需导出
}

父组件(发布消息):

import React, { Component } from 'react'
import Child from './pages/Child'

// 在App组件中生产数据,这样下面的子孙组件就可以调用此context对象来消费数据
import { Provider } from './context/appContext'

class App extends Component {
  state = {
    name: '张三',
    setName: name => this.setState({ name })
  }

  render() {
    return (
      <div>
        {/* value属性就是生产的数据源 */}
        <Provider value={this.state}>
          <Child />
        </Provider>
      </div>
    )
  }
}

export default App

子组件(组件消费):

import React, { Component } from 'react'

// 假设现在当前组件是App组件下面的很深的子孙组件
import ctx, { Consumer } from '../../context/appContext'

class Child extends Component {
  // 类组件中context还可以换一个方案来消费,定义好后,就可以通过成员属性 this.context来获取数据
  static contextType = ctx

  render() {
    return (
      <div>
        {/* 消费方案1 */}
        {/* <Consumer>{state => <h3>{state.name}</h3>}</Consumer> */}
        {/* 消费方案2(常用方案) */}
        <h3>{this.context.name}</h3>
        <button
          onClick={() => {
            // 这里更改的是父组件中数据源的数据,父组件一改,父组件下所有的子孙组件都会更新
            this.context.setName(Date.now())
          }}
        >
          ++++
        </button>
      </div>
    )
  }
}

export default Child

在这里插入图片描述

4. 状态提升案例:toDoList

父组件(App.jsx):

import React, { Component } from 'react'
import Todo from './todo'
import './app.css'

class App extends Component {
  render() {
    return (
      <div>
        <h3 className="app-title">App组件</h3>
        <Todo />
      </div>
    )
  }
}

export default App

子组件(index.jsx):

import React, { Component } from 'react'
import Form from './Form'
import List from './List'

class Todo extends Component {
  state = {
    todos: []
  }

  addTodo = todo => this.setState(state => ({ todos: state.todos.concat(todo) }))

  render() {
    let { todos } = this.state
    return (
      <div>
        <Form addTodo={this.addTodo} />
        <List todos={todos} />
      </div>
    )
  }
}

export default Todo

子组件(form.jsx):

import React, { Component } from 'react'

class Form extends Component {
  onEnter = e => {
    if (e.key === 'Enter') {
      let value = e.target.value.trim()
      e.target.value = ''
      this.props.addTodo({
        id: Date.now(),
        title: value,
        done: false
      })
    }
  }

  render() {
    return (
      <div>
        <input type="text" onKeyUp={this.onEnter} />
      </div>
    )
  }
}

export default Form

子组件(list.jsx):

import React, { Component } from 'react'
import style from './style.module.css'

class List extends Component {
  render() {
    let { todos } = this.props
    return (
      <div>
        <ul>
          {todos.map(({ id, title, done }) => (
            <li key={id}>
              <span className={done ? style.title : ''}>{title}</span>
              <span>删除</span>
            </li>
          ))}
        </ul>
      </div>
    )
  }
}

export default List

在这里插入图片描述

相关文章:

  • SQL入门(三)数据库之表连接(内联外联的区别)
  • BUUCTF-社团考核
  • 基于卷积神经网络故障诊断模型的 t-SNE特征可视化
  • 不写DAX实现TopN和其他
  • ArrayList实现简易扑克牌
  • 程序员薪资有多高?8大互联网大厂纷纷开奖,校招真的杀疯了|最值得投递的大厂|应届生必看
  • 集成学习详解
  • 微信小程序开发入门与实战(组件的使用)
  • 【Linux篇】第十篇——基础IO(系统文件IO+文件描述符+重定向+文件系统+软硬链接)
  • java计算机毕业设计食品点评及售卖系统源代码+数据库+系统+lw文档
  • 一起Talk Android吧(第三百八十七回:LiveData)
  • 整理了几个100%会踩的Python细节坑,提前防止脑血栓
  • 计算机视觉 神经网络,神经网络模型可视化
  • day011--mysql中的不可逆加密函数,信息函数及转换函数
  • 基于java厨艺交流平台计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  • JavaScript 如何正确处理 Unicode 编码问题!
  • Angularjs之国际化
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • JavaScript 奇技淫巧
  • JavaScript设计模式与开发实践系列之策略模式
  • mongo索引构建
  • Python 基础起步 (十) 什么叫函数?
  • Python连接Oracle
  • ubuntu 下nginx安装 并支持https协议
  • vue学习系列(二)vue-cli
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 两列自适应布局方案整理
  • 区块链共识机制优缺点对比都是什么
  • 少走弯路,给Java 1~5 年程序员的建议
  • 阿里云ACE认证之理解CDN技术
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​secrets --- 生成管理密码的安全随机数​
  • # Apache SeaTunnel 究竟是什么?
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (39)STM32——FLASH闪存
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (独孤九剑)--文件系统
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (七)c52学习之旅-中断
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • *2 echo、printf、mkdir命令的应用
  • .NET 4.0中的泛型协变和反变
  • .Net CF下精确的计时器
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .NET MVC 验证码
  • .Net Web窗口页属性
  • @Not - Empty-Null-Blank
  • [ C++ ] STL---仿函数与priority_queue
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • [17]JAVAEE-HTTP协议