使用 react 经常会遇到几个组件需要共用状态数据的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。
原理:父组件基于属性把自己的一个fn函数传递给子组件,子组件在某些操作下把fn执行,在执行fn的过程中把父组件中的一些属性信息进行了修改,从而影响相关子组件的重新渲染。
直接看代码
<Vote title={'标题一'}></Vote> //调用
vote.js文件
import React from 'react';
import VoteHeader from './voteHeader.js'
import VoteBody from './voteBody.js'
import VoteFooter from './voteFooter.js'
class Vote extends React.Component{
constructor(){
super()
this.state = {
n: 0,
m: 0
}
}
handleNum = (type)=> {
if (type === 1) {
this.setState({
n: this.state.n+1
})
} else {
this.setState({
m: this.state.m+1
})
}
}
render() {
let {title} = this.props;
let {n, m} = this.state;
let {handleNum} = this;
return (
<div>
<VoteHeader title={title}></VoteHeader>
<VoteBody n={n} m={m}></VoteBody>
//将父组件函数传递给子组件调用
<VoteFooter handleNum={handleNum}></VoteFooter>
</div>
)
}
}
export default Vote;
VoteHeader.js文件
import React from 'react';
class VoteHeader extends React.Component{
constructor(){
super()
}
render() {
let {title} = this.props;
return (
<div>{title}</div>
)
}
}
export default VoteHeader;
VoteBody.js文件
import React from 'react';
class VoteBody extends React.Component{
constructor(){
super()
}
render() {
let {n, m} = this.props;
return (
<div>
<div>赞成{n}票</div>
<div>反对{m}票</div>
</div>
)
}
}
export default VoteBody;
VoteFooter.js文件
import React from 'react';
class VoteFooter extends React.Component{
constructor(){
super()
}
render() {
let {handleNum} = this.props;
return (
<div>
//这个地方通过操作父组件函数改变父组件的属性值
<button onClick={e => handleNum(1)}>赞成</button>
<button onClick={e => handleNum(0)}>反对</button>
</div>
)
}
}
export default VoteFooter;
基于上下文管理组件信息的传递
上下文也是依托组件嵌套关系完成的,它的优势在于:当前组件(祖先组件)设置一些上下文,后代所有组件(儿子或孙子等)都可以随时获取使用,而不需要调取组件的时候层层传递。
直接看代码
<Vote title={'标题一'}></Vote> //调用
vote.js文件
import React from 'react';
import PropTypes from 'prop-types';
import VoteHeader from './voteHeader1.js'
import VoteBody from './voteBody1.js'
import VoteFooter from './voteFooter1.js'
class Vote extends React.Component{
//设置后代需要使用的上下文及类型
static childContextTypes = {
title: PropTypes.string,
n: PropTypes.number,
m: PropTypes.number,
handleNum: PropTypes.func
}
//获取后代需要的上下文信息(可以把这个方法理解为一个生命周期函数,在每一次render之前执行,return的值就是后期需要用到的上下文具体信息值)
getChildContext(){
let {title} = this.props;
let {n, m} = this.state;
let {handleNum} = this;
return {
title,
n,
m,
handleNum
}
}
constructor(){
super();
this.state = {
n: 0,
m: 0
}
}
handleNum = (type)=> {
if (type === 1) {
this.setState({
n: this.state.n+1
})
} else {
this.setState({
m: this.state.m+1
})
}
}
render() {
return (
<div>
//这里就不需要再手动传递props了
<VoteHeader></VoteHeader>
<VoteBody></VoteBody>
<VoteFooter></VoteFooter>
</div>
)
}
}
export default Vote;
VoteHeader.js文件
import React from 'react';
import PropTypes from "prop-types"
class VoteHeader extends React.Component{
//在后代组件中,我们需要用到哪些上下文信息,一定要指定当前需要使用的信息值类型(而且必须和祖先指定的一样),否者无法基于context获取
static contextTypes = {
title: PropTypes.string
}
constructor(){
super()
}
render() {
return (
//通过上下文的值来进行渲染
<div>{this.context.title}</div>
)
}
}
export default VoteHeader;
VoteBody.js文件
import React from 'react';
import PropTypes from "prop-types"
class VoteBody extends React.Component{
static contextTypes = {
n: PropTypes.number,
m: PropTypes.number
}
constructor(){
super()
}
render() {
let {n, m} = this.context;
return (
<div>
<div>赞成{n}票</div>
<div>反对{m}票</div>
</div>
)
}
}
export default VoteBody;
VoteFooter.js文件
import React from 'react';
import PropTypes from "prop-types";
class VoteFooter extends React.Component{
static contextTypes = {
handleNum: PropTypes.func,
}
constructor(){
super()
}
render() {
let {handleNum} = this.context;
return (
<div>
<button onClick={e => handleNum(1)}>赞成</button>
<button onClick={e => handleNum(0)}>反对</button>
</div>
)
}
}
export default VoteFooter;