文章出自个人博客 https://knightyun.github.io/2020/09/03/js-react-props,转载请申明


父级传向子级

这应该是最常见的一种场景,通过在子组件上写 props,将数据从父组件中传递到子组件,子组件再从 this.props 中获取相应的值,这样可以根据传入值的不同返回不同的状态,即实现组件的复用;例如:

import React from 'react';// 父组件
class Parent extends React.Component {message = 'Hello world!';render() {return (<Child myProp={this.message} />);}
}// 子组件
class Child extends React.Component {message = this.props.myProp;render() {// Hello world!return (<div>{this.message}</div>);}
}export default Parent;

多层传值

上述方法只用于单层数据传递,即父级传向子级,如果子级又存在子级,甚至向下递推,那么父组件要传值给后代组件,就要逐层向下传递,类似下面的情况:

import React from 'react';class Parent extends React.Component {render() {return <Child myProp="hello" />}
}class Child extends React.Component {render() {return <Grandchild myProp1={this.props.myProp} />}
}class Grandchild extends React.Component {render() {// helloreturn <div>{this.props.myProp1}</div>}
}export default Parent;

如果层数再多一些就是书写噩梦了,所以 React 提供了 context 机制,解决了深层传值的问题,现在来改造上面的代码:

import Reac from 'react';// 首先需要创建一个自定义 context
// 该方法接收一个参数作为 context 的默认值
const myContext = React.createContext();
// 获取包裹组件,用于包裹需要应用 context 的组件
const { Provider } = myContext;class Parent extends React.Component {value = {message: 'hello',};render() {// 通过包裹器的 value 属性向下传递指定值return (<Provider value={this.value}><Child /></Provider>);}
}class Child extends React.Component {render() {return <Grandchild />}
}class Grandchild extends React.Component {// 在需要获取祖代传递的 context 值的后代组件中,// 声明 contextType 静态属性,值为之前创建的 context;static contextType = myContext;render() {// 最后使用 this.context 就能获取到之前// 在 Provider 中传入的 value 值;return <div>{this.context.message}</div>// hello}
}export default Parent;

需要注意的是,由于提供方和调用方需要使用同一个使用 React.createContext() 创建的 context,所以如果父组件和要调用 context 的子组件不在同一个文件中的话,则需要考虑通过 exportimport 来实现引用,但是这样组件间的耦合度又增加了一层,React 官方建议使用 组合 方式取代上述的 继承 方式,下面再次对上述代码进行改造:

import React from 'react';class Parent extends React.Component {value = {message: 'hello',};render() {return (<Child>{this.value.message}</Child>);}
}class Child extends React.Component {render() {// this.props.children 会指向父组件在子组件中嵌入的数据或组件return (<div>{this.props.children}</div>);}
}export default Parent;

子级传向父级

React 中似乎没有提供子级向父级直接传值,类似 props 的方法或途径,可以通过一些间接手段实现,开发中常见的处理方式就是子组件调用父组件通过 props 传入的处理函数,对需要传递的值进行处理;例如:

import React from 'react';class Parent extends React.Component {state = {message: '',};handleMsg(msg) {this.setState({message: msg,});}render() {// Helloreturn (<>{this.state.message}<Child onMsg={(msg) => this.handleMsg(msg)}/></>);}
}class Child extends React.Component {handleClick() {this.props.onMsg('Hello');}render() {return (<buttononClick={() => this.handleClick()}>Clike me</button>);}
}export default Parent;

简单梳理一下流程:

  • 父组件提前声明数据处理逻辑,该方法接收传入的值,然后进行相应处理;
  • 父组件将该方法通过 props 传递给子组件;
  • 子组件触发一些行为,得到了将要传递给父组件的值;
  • 子组件通过 this.props 调用父组件传入的处理函数,并将要传递的值作为该函数的参数;
  • 处理函数开始执行,由于其是在父组件的作用域中声明的,所以也能访问父组件中的一些数据,比如 state,相当于在父组件中处理子组件传入的数据;
  • 处理函数更新 state 状态值,随后其他访问该 state 的地方也会随即更新;

同级间传递

状态提升

这是 React 官网提到的一个概念,即多个组件都在重复使用同一个状态值,可以将这个值 提升 至父组件中保存,相当于数据复用;当然如果想实现一个子组件向另一个子组件传值,也可以通过父组件这层“媒介”;下面举例说明:

import React from 'react';class Parent extends React.Component {state = {msg: 'hello',}handleChangeMsg(msg) {this.setState({msg: msg,});}render() {return (<><ChildLabel msg={this.state.msg} /><ChildButtononChangeMsg={(msg) => this.handleChangeMsg(msg)}/></>);}
}class ChildLabel extends React.Component {render() {return <span>{this.props.msg}</span>}
}class ChildButton extends React.Component {render() {return (<buttononClick={() => this.props.onChangeMsg('world')}>Change</button>)}
}export default Parent;

这样在页面中点击子组件 <ChildButton /> 中的按钮时,子组件 <ChildLabel /> 中的文本便会发生相应变化,成功获取传入的值;这里的操作相当于子组件先向父组件传值,使得父组件状态变化,然后使用该状态的另一子组件就会相应地变化;

Refs

Refs 是 React 提供的另一种机制,React 中典型数据流是通过 props 传递,而 refs 则相当于提供了直接操纵组件或 DOM 元素的一种途径,强制修改元素;因此官网也建议避免过度使用 refs,防止应用变得难以理解或“失控”;下面通过举例简单说明其用法:

import React from 'react';class Parent extends React.Component {// 首先需要声明 refmyRef = React.createRef();handleClick(msg) {// 通过 ref 的 current 属性实现对该元素的引用,// 然后就能想操作正常 DOM 一样实现控制;this.myRef.current.innerText = msg;}render() {// 对需要被引用的元素使用 ref 属性,值为之前所创建的 refreturn (<><span ref={this.myRef}>hello</span><buttononClick={() => this.handleClick('world')}>Change</button></>);}
}export default Parent;

在页面上点击按钮后,前面的文本同样会发生改变,即 DOM 元素的元素属性 innerText 值被成功修改,如需使用其他原生属性或方法同理;

Refs 转发

虽然 Refs 提供了直接访问组件或元素的途径,但是它却访问不了组件中的组件,这是 React 层故意为之,隐藏组件实现细节与渲染结果,防止组件的 DOM 结构被过度依赖;但有一些特殊情况下确实需要访问组件内部的组件的话,React 也提供了另外一种机制,即 Refs 转发(Refs Forwarding);顾名思义,组件 A 不能直接使用 ref 访问组件 B 中的组件 C,但是可以通过组件 B 转发 ref 给组件 C,这里改造一下上面 Refs 中的例子,我们在 <Parent /><span> 之间再加一层组件,再实现对其的操作:

class Parent extends React.Component {myRef = React.createRef();handleClick(msg) {this.myRef.current.innerText = msg;}render() {// 对子组件正常使用 refreturn (<Childref={this.myRef}handleClick={this.handleClick.bind(this)}/>);}
}// 使用 React.forwardRef 方法转发 ref 给下一层组件
const Child = React.forwardRef((props, ref) => {return (<><span ref={ref}>hello</span><buttononClick={() => props.handleClick('world')}>Change</button></>);
});
const Child = React.forwardRef((props, ref) => {return (<><span ref={ref}>hello</span><buttononClick={() => props.handleClick('world')}>Change</button></>);
});

Refs 转发需要使用 React.forwardRef() 方法创造组件,该方法接收一个回调函数做为参数,该回调函数接收两个入参,第一个是传进组件的 props,第二个是传进组件的的 ref,通过内部逻辑决定 ref 再转发给谁,回调函数的返回值是最终生成的组件;页面加载组件后,点击按钮,就能像直接使用 ref 一样改变展示的文本值了;


技术文章推送 手机、电脑实用软件分享

React 组件间传值的几种情形相关推荐

  1. 【Vue】组件间传值的三种方式:父传子,子传父,非父子传值

    引用官网的一句话:父子组件的关系可以总结为 prop 向下传递,事件向上传递.父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息,如下图所示: 1,父组件传值给子组件 代码: &l ...

  2. vue组件间传值的几种方法

    一丶父子组件传值 先在父组件中给子组件的自定义属性绑定一个 父组件的变量 <template class="father"><child :自定义属性名=&quo ...

  3. vue项目原理分析-1:组件间传值

    整个项目目录(create project后) vue.config.js的配置 // vue.config.js 常⽤配置 module.exports = {devServer:{port:333 ...

  4. 简单教你React父子组件间平级组件间传值

    国庆充电特辑: 堵车堵死,废话不多说直接上菜. 1.父组件对子组件传值 利用props属性传值 class Component extends React.Component {constructor ...

  5. vue用公共组件页面传值_vuejs几种不同组件(页面)间传值的方式

    在应用复杂时,推荐使用vue官网推荐的vuex,以下讨论简单SPA(single-page application 简称为 SPA)中的组件间传值. 一.路由传值 路由对象如下图所示: 在跳转页面的时 ...

  6. Vue组件间传值详解

    文章目录 1. 父组件向子组件传值 1.1 描述 1.2 props接收数据: 2. 子组件向父组件传值 3. 兄弟组件间传值 4. 事件总线 5. Ref 6. root/parent/childr ...

  7. uniapp 子组件 props拿不到数据_总结下React组件间的通讯

    这是个老话题了. 随着组件化开发成为主流,每个组件都有完善的生命周期,大家可以在生命周期内做一些事情,每个组件有自己的状态管理机制.同时,每个组件都是独立的.这能提高大家的开发效率,规范化开发. 今天 ...

  8. 六十三、Vue中非父子(兄弟)组件间传值,插槽的使用和作用域插槽(非常重要)

    2020/10/18 . 周日.今天又是奋斗的一天. @Author:Runsen @Date:2020/10/18 写在前面:我是「Runsen」,热爱技术.热爱开源.热爱编程.技术是开源的.知识是 ...

  9. vue组件间传值的六种方法

    一. vue组件间传值 1. 父组件向子组件进行传值props 父组件代码: <template><div>父组件:<input type="text" ...

最新文章

  1. MySQL数据库--连接
  2. tabbar怎么些_vue 做的tabBar组件
  3. 关于myBatis的问题There is no getter for property named 'USER_NAME' in 'class com.bky.model.实例类'...
  4. windows server2008无法将本地文件复制到远程计算机,windows2008/2012无法从本地复制文件到远程服务器处理方法...
  5. 适合python爬虫使用的浏览器_python爬虫:使用Selenium模拟浏览器
  6. sharepoint配置问题解决方案
  7. FreeEIM 2.0 beta 发布
  8. 国内人气设计师交流平台集设
  9. ubuntu12.04 + virtualbox
  10. 计算机职称专业分类明细,职称分类一览表
  11. 启动tomcat8时出现springfox.documentation.spi.service.contexts.OperationContext.headers()Ljava/util/Set;错误
  12. python爬取京东商品_Python爬取京东的商品分类与链接
  13. 类似endnote_Mendeley与EndNote类似的免费文献管理软件简介 | 科研动力
  14. 基于 RK3399 5G 通信和图像增强算法的交通监控系统设计
  15. 一IT项目经理的总结
  16. eclipse的启动失败提示发生了错误,请参阅日志文件
  17. LUOGU1438无聊的数列
  18. C++ 编译宏的一些符号
  19. 04_UUID128修改与广播名
  20. java 判断类型_Java变量类型识别的3种方式

热门文章

  1. Java并发编程系列
  2. 《Python自然语言处理》——1.8 练习
  3. Android 沉浸式状态栏
  4. 微信开发七(配置js-SDK,步骤2)
  5. Collections.sort的两个方法
  6. rhel6.1 kvm安装virtio驱动
  7. MCSE2003学习之八
  8. java web 统计_Java web网站访问量的统计
  9. flutter图片点击跳转_Flutter系列之Platform Channel使用详解
  10. 判断整除(动态规划,递推)