组件(进阶版)
主要内容为组件之间如何进行通信,父子组件,兄弟组件,跨组件通信等。
1、组件通信
我们都知道一个完整的页面功能,是由多个组件组合在一起完成的,但是我们知道组件之间并不可能是完全没有关联的,比如:我们通常看到的搜索框,上面是搜索框、下面会显示历史记录;事实上,它是由两部分组件共同完成的,这就需要组件之间有联系,所以这就是我们所说的组件通信。
但是我们都知道组件是一个封闭的资源,那我们如何让他们之间实现通信呢?我们如何才能让搜索框搜索完让他显示在历史记录的组件中呢?这就需要组件的props来实现了。
2、组件的props
1)作用:接收传递给组件的数据
2)传递方式:给组件标签添加属性
3)接收方式:
a)函数组件:props.标签(函数中要传递props参数)
b)类组件:this.props.标签
4)特点:
a)传递数据的类型没有限制、“”默认传递字符串、{}可以传递别的类型、甚至可以传递JSX、函数等
b)只读、不可修改值
c)类组件若写了构造函数constructor,则需把props参数传递过去super也需要传递props参数
3、props进阶
1)props的children属性
当组件标签中存在子节点时,就表示组件标签的子节点
childern属性和其他props一样,值既可以是文本也可以是组件、React元素、函数等
2)props校验
对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据,若传入的数据格式不对,可能导致组件内部报错,而在这个时候组件使用者不知道错误原因究竟是什么。所以props校验的作用就显现出来了!
**props校验:**在创建组件时,就指定props的类型、格式等。
作用:捕获使用组件时因为props导致的错误,给出明确的错误提示,增强组件的健壮性。
常见类型:array、bool、func、number、object、string
React元素类型:element
必填项:isRequired
特定结构对象:shape({})
3)props默认值
在没传入props时生效,传入时以传入为准
4、组件通讯的三种方式
1)父组件传递数据给子组件
a)父组件提供要传递的数据(state)
b)给子组件标签添加属性,值为state中的数据
c)子组件通过props接收父组件中传递的数据
import React from 'react'
import ReactDOM from 'react-dom'
///父组件
class Hello extends React.Component {
state = { Name: '小王' }
render () {
return (
<div className='parent'>
要传递给子组件的数据:<Child name={this.state.Name} />
</div>
)
}
}
///子组件
function Child (props) {
return (
<div className='child'>
<p> 子组件接收到的数据:{props.name} </p>
</div>
)
}
///渲染数据
ReactDOM.render(<Hello />, document.getElementById('root'))
2)子组件传递数据给父组件
父组件提供一个回调函数用于接收数据(谁要接收数据谁就提供回调函数)
将这个函数作为属性的值,传递给子组件,子组件通过props调用这个回调函数将值传递给父组件(谁传数据谁就调用)
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
///父组件
///父组件要接受数据所以父组件要有回调函数
class Parent extends React.Component {
state = {
msg: ''
}
//提供回调函数用于接收数据
getChildMessage = data => {
console.log(data)
this.setState = ({
msg: data
})
}
render () {
return (
<div className='parent'>
{/* 将函数通过getMsg标签的传递给子组件 */}
父组件:{this.state.msg}
<Child getMsg={this.getChildMessage} />
</div>
)
}
}
///子组件
///子组件要调用回调函数 把值传给父组件
class Child extends React.Component {
///要把这个值传递给父组件
state = {
msg1: 'AAAA++++'
}
dianJi = () => {
///子组件调用父组件中传递过来的回调函数
///通过调用从父组件拿过来的方法把子组件的值传递给父组件
this.props.getMsg(this.state.msg1)
}
render () {
return (
<div className='child' >
{/* 子组件:{''} */}
<button onClick={this.dianJi}>通过点击按钮触发传递数据</button>
</div>
)
}
}
///渲染数据
ReactDOM.render(<Parent />, document.getElementById('root'))
3)兄弟组件(状态提升)
将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态。
公共父组件用处:提供共享状态让两个兄弟组件都可以使用这个状态、提供操作共享状态的方法(比如这个数据原来是B组件的,若组件A想用组件B的数据,那组件A就可以通过公共父组件来获得B的数据)
想要通讯的子组件只需通过props接收状态或操作状态的方法
import React from 'react'
import ReactDOM from 'react-dom'
//父组件
class Parent extends React.Component {
//共享状态
state = {
count: 0
}
//定义一个修改状态的方法 因为state是私有数据 所以只有自己组件内部方法才可以调用
onIncreament = () => {
this.setState({
count: this.state.count + 1
})
}
render () {
return (
<div>
{/* 子组件1 父组件到子组件的传递*/}
<Child1 count={this.state.count} />
{/* 子组件2 */}
<Child2 onIncreament={this.onIncreament} />
</div>
)
}
}
///子组件1:用来显示计数器字样
const Child1 = (props) => {
return <p>计数器:{props.count}</p>
}
//子组件2:用来显示按钮+1现象
const Child2 = (props) => {
return <button onClick={() => props.onIncreament()}>+1</button>
}
///渲染数据
ReactDOM.render(<Parent />, document.getElementById('root'))
5、Context跨组件传递
当我们学习了父子组件之间的通讯,当我们遇到一个父组件包含一个子组件,子组件又包含子组件,又包含…此时我们能够想到使用父组件到子组件的通信问题,但是其实这会使用很多次通讯,这也非常的复杂,所以我们找到了更好的通讯方式—Context跨组件传递数据。
使用步骤:
1)调用React.createContext()创建Provider数据提供者和Consumer数据消费者两个组件
2)使用Provider组件作为父节点,把你想要传出数据的组件的render()内容包裹起来
3)在Provider设置value属性,表示要传递的数据是什么
4)在想要接收数据的组件中调用Consumer组件接收数据
{ data => <p>data参数表示接收到的数据{data}</p>}
import React from 'react'
import ReactDOM from 'react-dom'
const { Provider, Consumer } = React.createContext()
///父组件
class Parent extends React.Component {
render () {
return (
<Provider value='AAA'>
<div>
<Node />
</div>
</Provider>
)
}
}
const Node = props => {
return (
<div>
<Child />
</div>
)
}
const Child = props => {
return (
<div>
<Consumer>
{data => <p>子节点:{data}</p>}
</Consumer>
</div>
)
}
ReactDOM.render(<Parent />, document.getElementById('root'))