组件通讯介绍
组件是一个独立且封闭的单元,默认情况下,组件只能进行内部的数据传递。在组件化过程中,我们将一个完整的功能拆分成多个组件,以更好的完成整个应用的功能。而在这个过程中,多个组件之间不可避免的要共享某些数据。为了实现这些功能,就需要打破组件的独立封闭性,让其与外界沟通,这就叫组件通讯
组件的props
组件是封闭的,要接收外部数据需要通过props
props的作用:接收传递给组件的数据
传递数据:给组件标签添加属性
接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据
2.1 函数组件的组件通讯
通过参数props接收数据
// 2.接收数据
const Hello = props => {
console.log(props);
return (
<div>
<h1>props: {props.name} {props.age} </h1>
</div>
)
}
// 1.传递数据
// 将要传递的数据当做属性来写
ReactDOM.render(<Hello name='jack' age={19}/>, document.getElementById('root'))
2.2 类组件的组件通讯
通过this.props接收数据
// 类组件的组件通讯
class Hello extends React.Component {
render() {
console.log(this.props);
return (
<div>
<h1>props: {this.props.name} {this.props.age} </h1>
</div>
)
}
}
// 1.传递数据
ReactDOM.render(<Hello name='rose' age={19} />, document.getElementById('root'))
2.3 props的特点
可以传递任意类型的数据
函数对象,JSX都可以传递
// 2.接收数据
const Hello = props => {
props.fn()
return (
<div>
<h1>props: {props.name} {props.age} </h1><br/>
<h2>{props.colors}</h2><br/>
<h2>{props.tag}</h2>
</div>
)
}
// }
// 1.传递数据
ReactDOM.render(
<Hello
name='rose'
age={19}
fn={() => console.log('这是一个函数对象')}
colors={['red','pink','blue']}
tag={<p>这是一个标签</p>}
/>,
document.getElementById('root'))
props是只读的对象,只能读取属性的值,不能进行修改
给props.name赋值
props.name = 'tom'
报错
使用类组件时,如果写了构造函数,应该将props传给super()
否则,将无法在构造函数中获取到props!!!
未传递props
class Hello extends React.Component {
constructor() {
super()
console.log(this.props);
}
render() {
// console.log(this.props);
return (
<div>
<h1>props: {this.props.name} {this.props.age} </h1>
</div>
)
}
}
ReactDOM.render( <Hello name='rose' age={19} />, document.getElementById('root'))
传递props 推荐使用
class Hello extends React.Component {
constructor(props) {
super(props)
console.log(props);
}
render() {
// console.log(this.props);
return (
<div>
<h1>props: {this.props.name} {this.props.age} </h1>
</div>
)
}
}
ReactDOM.render( <Hello name='rose' age={19} />, document.getElementById('root'))
组件通讯的三种方式
3.1 父组件传子组件
步骤
1.父组件提供要传递的state数据
2.给子组件标签添加属性,值为state中的数据
3.子组件中通过props接收父组件中传递来的数据
class Parent extends React.Component {
state = {
lastName: '王'
}
render() {
return (
<div className='parent'>
父组件:
<Child name={this.state.lastName}></Child>
</div>
)
}
}
// 子组件
const Child = props => {
console.log('子组件:',props);
return (
<div className="child">
<p>子组件,接收到父组件的数据: {props.name}</p>
</div>
)
}
ReactDOM.render(<Parent />, document.getElementById('root'))
3.2 子组件传父组件
利用回调函数,父组件提供回调函数,子组件调用,将要传递的数据作为回调函数的参数
1.父组件提供函数getChildMsg来接收数据
2.子组件调用getChildMsg传递函数
3.调用父组件中的方法getMsg 将参数传递进去
4 父组件接收数据
// 子组件传父组件
class Parent extends React.Component {
state = {
parentMsg: ''
}
getChildMsg = msg => {
console.log('接收到子组件的数据', msg);
this.setState({
parentMsg: msg
})
}
render() {
return (
<div>
父组件: {this.state.parentMsg}
<Child getMsg={this.getChildMsg}/>
</div>
)
}
}
// 子组件
class Child extends React.Component {
state = {
msg: 'study'
}
handleClick = () => {
this.props.getMsg(this.state.msg)
}
// 子组件通过props调用回调函数
render() {
return (
<div className="child">
子组件:<button onClick={this.handleClick}>点击,给子组件传递数据</button>
</div>
)
}
}
ReactDOM.render(<Parent/>, document.getElementById('root'))
3.3 兄弟组件
1.将共享状态提升到最近的公共父组件中,有公共父组件管理这个状态
2.思想:状态提升
3.公共父组件职责:1.提供共享状态 2.提供操作共享状态的方法
4.要通讯的子组件只需通过props接收状态或操作状态的方法
// 父组件
class Counter extends React.Component {
// super()
state = {
count: 0
}
onIncrement = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
{/* 父组件中的状态通过属性传递给子组件 */}
<Child1 count={this.state.count}/>
<Child2 onIncrement={this.onIncrement}/>
</div>
)
}
}
// 子组件中通过props接收数据
const Child1 = (props) => {
return <h1>计数器:{props.count}</h1>
}
const Child2 = (props) => {
return <button onClick={() => props.onIncrement()}>+1</button>
}
ReactDOM.render(<Counter/>, document.getElementById('root'))
Context
如果两个组件嵌套多层,可以使用Context实现组件通讯
Context提供两个组件:Provider Consumer
Provider:提供数据
Consumer:消费数据
const {Provider, Consumer} = React.createContext()
class Counter extends React.Component {
render() {
return (
<Provider value="rose">
<div className='Counter'>
<Child1 />
</div>
</Provider>
)
}
}
// 子组件中通过props接收数据
const Child1 = (props) => {
return (
<div className='Child1'>
<Child2 />
</div>
)
}
const Child2 = (props) => {
return (
<div className='Child2'>
<Child3 />
</div>
)
}
const Child3 = (props) => {
return (
<div className='Child3'>
<Child4 />
</div>
)
}
const Child4 = (props) => {
return (
<Consumer>{data => <p>我是用Context拿来的值---{data}</p>}</Consumer>
)
}
ReactDOM.render(<Counter />, document.getElementById('root'))
props深入
children属性
文本节点
const Parent = props => {
console.log(props);
return (
<div>
<h1>我是你的父组件 {props.children}</h1>
</div>
)
}
ReactDOM.render(<Parent>我是你的子组件--文本版本</Parent>, document.getElementById('root'))
JSX
const Parent = props => {
console.log(props);
return (
<div>
<h1>我是你的父组件 {props.children}</h1>
</div>
)
}
ReactDOM.render(<Parent><p>我是你的子组件--JSX版本</p></Parent>, document.getElementById('root'))
组件
const Parent = props => {
console.log(props);
return (
<div>
<h1>我是你的父组件 {props.children}</h1>
</div>
)
}
const Children = props => {
return (
<div className='Children'>
<p>我是你的子组件--组件版本</p>
</div>
)
}
ReactDOM.render(<Parent>我是你的子组件--文本版本</Parent>, document.getElementById('root'))
props校验
对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据
==props校验:==允许在创建组件的时候,就指定props的类型、格式等
作用:捕获使用组件时因为props导致的错误,给出明确错误提示,增加代码的健壮性
步骤
1.安装prop-types (yarn add prop-types)
2.引入prop-types安装包 (import PropTypes from ‘prop-types’)
3.使用 组件名.propTypes={} 来给组件的props添加校验规则
4.校验规则通过propTypes指定
const App = props => {
// 拿到子组件的属性
const arr = props.colors
const lis = arr.map((item, index) => <li key={index}>{item}</li>)
return <ul>{lis}</ul>
}
App.propTypes = {
colors: PropTypes.array
}
ReactDOM.render(<App colors = {['red','yello','pink']}></App>, document.getElementById('root'))
组件的生命周期
声明周期的三个阶段
创建时(挂载阶段)
执行时机:组件创建时(页面加载时)
执行顺序:constructor() -> render() -> componentDidMount
钩子函数 | 触发时机 | 作用 |
---|---|---|
constructor | 创建组件时,最先执行 | 1.初始化state 2.为事件处理程序绑定this |
render | 每次组件调用时都会触发 | 渲染UI(不能调用setState()) |
componentDidMount | 组件挂载(完成渲染)后 | 1.发送网络请求 2.DOM操作 |
更新阶段
执行时机:1.New props 组件接收到新的属性 2.setState() 3.forceUpdate()
以上任意一种变化,都会导致组件重新渲染
执行顺序: render() -> componentDidUpdate() 先渲染完成,再去渲染构造函数
钩子函数 | 触发时机 | 作用 |
---|---|---|
render | 每次组件调用时都会触发 | 渲染UI(不能调用setState()) |
componentDidMount | 组件挂载(完成渲染)后 | 1.发送网络请求 2.DOM操作 3.要用setSate 和 Ajax请求要放在if中 |
卸载阶段
执行时机:组件从页面中消失时
钩子函数 | 触发时机 | 作用 |
---|---|---|
componentWillUMount | 组件卸载(从页面中消失) | 执行清理工作(清理定时器等) |