组件
组件,指的是能完成某个特定功能的独立的、可重用的代码。Component是所有组件的基类,提供了很多组件共有的功能;
React 为每个组件提供了生命周期钩子函数去相应不同的时刻-----创建时(实例化)、存在期及销毁时。
React 组件之间通信是单向的,数据只能由一方传到另一方。
组件之间的关系有:
- 父组件向子组件传递值
- 子组件向父组件传递值
- 兄弟组件之间通信
父组件代码
import React, { Component } from 'react';
import { Card, Row, Col, Button, Tooltip, Tabs } from 'antd';
import Children1 from './Children1';
import Children2 from './Children2';
import Children3 from './Children3';
import Context from './ChildContext';
const { TabPane } = Tabs;
class Index extends Component {
/**
* constructor 构造方法
* @param props
* ES6 对类的默认方法,通过 new 命令生成对象实例时自动调用该方法。
* 该方法是类必有的,如果没有显示定义,则会默认添加空的 constructor()方法
*
* 如果想在constructor中使用this.props,super必须加props
*/
constructor(props) {
// todo 如果constructor中不通过super来接收props,在其他生命周期,
// 诸如componentWillMount、componentDidMount、render中能直接使用this.props吗??
// 结论:可以的,react在除了constructor之外的生命周期已经传入了this.props了,完全不受super(props)的影响。
/**
* super(props)
* 可以不写constructor, 一旦写constructor ,就必须在函数中写super()
* 此时组件才有自己的this, 在组件的全局中都可以实现this关键字
* 否则如果只是constructor 而不执行super() ,那么this 指向都是错的
*/
super(props);
this.state = {
msg: '父类消息',
name: 'parent',
index: 1,
child3C: { key: 'child3child' },
};
}
callBack = (msg, name, index) => {
this.setState({ msg, name, index });
};
/**
* 父组件 点击调用子组件2 中的函数
* @param e
*/
handleClick = e => {
e.stopPropagation();
const { msg, name, index } = this.state;
this.children2.handleChildren2Fn(`${msg}${index}`, `${name}${index}`);
this.setState({ index: index + 1 });
};
/**
* 点击修改父组件数据,可以相应更新子组件展示数据
* @param e
*/
handleChangeState = e => {
e.stopPropagation();
const { msg, name, index } = this.state;
this.setState({
msg: `${msg}${index + 1}`,
name: `${name}${index + 1}`,
index: index + 1,
});
};
/**
* 父组件Context上下文
* @param e
* Provider value 属性相当于getChildContext()
*/
handleContextBack = e => {
e.stopPropagation();
// const { child3C: { key: 'child3child' }, } = this.state;
const {
index,
child3C: { key },
} = this.state;
this.setState({
child3C: {
key: `${key}${index + 1}`,
},
});
};
render() {
const { msg, name, child3C } = this.state;
return (
{msg}:{name}
{
this.children2 = children;
}}
/>
);
}
}
export default Index;
一、父组件 与 子组件传递数据 Parent -> Child2
父组件向子组件传递值,可以给子组件通过props传递,自上而下进行传递。
在父组件中代码,将父组件中的state中的数据通过...展开,将父组件Parent中的信息,简洁的传递到子组件。
{this.children2 = children;}}
/>
我在demo中将传递函数有两个按钮,“P调用C2函数” 与 “P函数修改数据,同步C2数据”
按钮“P调用C2函数” 与 “P函数修改数据,同步C2数据”
1、 P函数修改数据,同步C2数据
这个按钮式,修改Parent数据,然后同步Children2的数据,点击按钮,调用onClick函数,此函数点击修改父组件数据,可以相应更新子组件展示数据。
父组件的props与state改变会导致子组件的生命周期发生变化,更新子组件数据。
/**
* 点击修改父组件数据,可以相应更新子组件展示数据
* @param e
*/
handleChangeState = e => {
e.stopPropagation();
const { msg, name, index } = this.state;
this.setState({
msg: `${msg}${index + 1}`,
name: `${name}${index + 1}`,
index: index + 1,
});
};
在子组件children2中,可以通过this.props 获取,如下 子组件2 代码。
2、 P调用C2函数 父组件调用子组件函数 (也是子组件传递函数到父组件)
父组件 点击调用子组件2 中的函数。由于组件之间通信是单向的,父组件可以传递给子组件,但是如果父组件需要调用子组件函数,需要进行特殊处理。
子组件2中定义函数,this 指向 children2
handleChildren2Fn = (msg, name) => {
this.setState({ msg, name });
};
在父组件
{this.children2 = children;}}/>
使用ref 方法。ref 方法可以接收一个回调函数,表示子组件加载完成之后执行的方法,回调函数的参数即为子组件的作用域this,把子组件的作用域this赋值给父组件,就可以用用子组件中的方法了。
/**
* 父组件 点击调用子组件2 中的函数
* @param e
*/
handleClick = e => {
e.stopPropagation();
const { msg, name, index } = this.state;
this.children2.handleChildren2Fn(`${msg}${index}`, `${name}${index}`);
this.setState({ index: index + 1 });
};
子组件2代码
import React, { Component } from 'react';
import { Card } from 'antd';
import isEqual from 'lodash/isEqual';
class Children2 extends Component {
constructor(props) {
super(props);
this.state = {
name: 'children2',
msg: 'children2 消息',
pName: props.name,
pMsg: props.msg,
};
}
/**
* getDerivedStateFromProps react17 新的生命周期
* 用于替换 componentWillReceiveProps ,用来控制props 更新 state的过程,他返回一个对象表示新的state.
* 每次渲染之前都会调用,不管初始挂载还是后面的 更新,都会调用,
* componentWillReceiveProps 只有父组件早场重新渲染才会调用
* 执行 setState 也会触发此函数
*
* static 中不允许用this
*
* 由于getDerivedStateFromProps 会在setState()后被调用,
* 并且它的返回值会被用于更新数据, 这意味着会在测触发setState()
* nextProps 第一个位置上的参数,未必是“新的” props,在组建中调用setState() 时,
* getDerivedStateFromProps 会被调用,此时nextprops并不是最新的。
*
*
* @param nextProps
* @param preState
* @returns {*}
*/
static getDerivedStateFromProps(nextProps, preState) {
if (isEqual(nextProps.msg, preState.msg)) {
return null;
}
const { msg, name, index } = nextProps;
return { pMsg: msg, pName: name, index };
}
handleChildren2Fn = (msg, name) => {
// console.log('调用children2 消息=========');
// console.log(this);
this.setState({ msg, name });
};
render() {
const { name, msg, pMsg, pName } = this.state;
return (
{pMsg} : {pName}
{msg} : {name}
);
}
}
export default Children2;
二、子组件 -> 传递数据 到父组件
子组件1代码
import React, { Component } from 'react';
import { Card, Button } from 'antd';
class Children1 extends Component {
constructor(props) {
super(props);
this.state = {
name: 'children1',
msg: 'children1 消息',
pName: props.name,
pMsg: props.msg,
};
}
/**
* handleClick 采用箭头函数的写法,目的是改变this的指向,
* 使得在函数单独调用的时候,函数内部的this依然指向children1 组件
* @param msg
* @param name
*/
handleClick = () => {
// console.log(this);
const { name, msg } = this.state;
this.props.callBack(msg, name);
};
render() {
const { name, msg, pMsg, pName } = this.state;
return (
{pMsg} : {pName}
{msg} : {name}
);
}
}
export default Children1;
如图所示,父组件、子组件一、子组件二