react系列(17)跨组件树传递数据 context

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zeping891103/article/details/83945388

在一个典型的 React 应用中,数据是通过 props 属性由上向下(由父及子)的进行传递的,当遇到多个层级多个组件间共享一个props参数,这种树形的由上而下的传参方式就显得过于繁琐。

一般多组件嵌套传参写法如下:

// 底层
function ThemedButton(props) {
  return <Button theme={props.theme} />;
}

// 中间
function Toolbar(props) {
  // Toolbar 组件必须添加一个额外的 theme 属性
  // 然后传递它给 ThemedButton 组件
  return (
    <div>
      <ThemedButton theme={props.theme} />
    </div>
  );
}

// 顶层
class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />;
  }
}

当这种嵌套足够多和层级足够深时,传递参数就显得很麻烦。

context 函数提供了一种在组件之间共享参数的方式,不必通过组件树的每个层级显式地传递 props。

 

React.createContext

创建一个context组件,并设定默认值。语法如下:

const {Provider, Consumer} = React.createContext(defaultValue);

Provider:接收一个将要被往下层层传递的props,该值需在组件树最顶层设置。一个Provider可以关联到多个Consumers。

Consumer:接收一个函数作为子节点,函数接收当前 context 的值,即Provider提供的props值或创建时的默认值并返回到一个dom节点。传递给函数的props值等于组件树中最接近自身的Provider的props值。

(贴士)如果上层的组件树没有一个匹配的 Provider或没有定义Provider,而此时渲染了一个 Consumer 组件,那么该Consumer组件将得到 createContext() 的 defaultValue 。

demo代码演示,创建context:

// globalprops-context.js
import React from 'react';

export const globalAutoProps = {
	data: {
		itemID: "ID0001",
		itemMsg: "Context共享参数"
	}
};

export const globalPropsContext = React.createContext(
	globalAutoProps.data // 默认值
);

组件树顶层:

// ContentProp.jsx
import React from 'react';
import ContentToolbar from './ContentToolbar.jsx';
import { globalPropsContext } from './globalprops-context.js';

class ContentProp extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			itemID: "ID0002",
			itemMsg: "Context共享参数"
		};
		this.clickHandle = this.clickHandle.bind(this);
	}

	clickHandle(e) {}

	render() {
        // 此处value为必填值
        return(
            <globalPropsContext.Provider value={this.state}>
                <ContentToolbar />
            </globalPropsContext.Provider>
            );
	}
}

export default ContentProp;

组件树的中层:

// ContentToolbar.jsx
import React from 'react';
import ContentButton from './ContentButton.jsx'

class ContentToolbar extends React.Component {
	constructor(props) {
		super(props);
		this.state = {};
	}

	render() {
		return(<ContentButton />);
	}
}

export default ContentToolbar;

组件树的底层:

// ContentButton.jsx
import React from 'react';
import { globalPropsContext } from './globalprops-context.js';

class ContentButton extends React.Component {
	constructor(props) {
		super(props);
		this.state = {};
	}

	render() {
		return(
                <globalPropsContext.Consumer>
      			{({itemID, itemMsg})  => <div>{itemID},{itemMsg}</div>}
    		</globalPropsContext.Consumer>
		);
	}
}

export default ContentButton;

通过运行脚本会发现,demo中树顶层设置的value值:value={this.state} 无需通过组件树中间层的参数过渡传递,在组件树底层也可以共享得到。

贴士:

1. Content.Provider 允许作用于多个上下文,如:

<AContent.Provider>
    <BContent.Provider></BContent.Provider>
</AContent.Provider>

2. 每当Provider的props值改变时, 作为Provider后代的所有Consumers都会重新渲染。 从Provider到其后代的Consumers传播不受shouldComponentUpdate方法的约束,因此即使祖先组件退出更新时,后代Consumer也会被更新。

不要仅仅为了避免在一个层级下的少数组件嵌套中传递 props 而使用 context,它是被用于在多个层级的多个组件需要访问相同数据的情景,如颜色主题、地点信息等。

 

另一种实现同样效果的技巧

通过直接提供Content和读取Content实现。通过 propTypes 与 childContextTypes 

// 顶层
import React from 'react';
import FluxDemo from './flux/FluxDemo.jsx';

class App extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			userinfo: "John"
		};
	}

	render() {
		return(
			<div>
				<FluxDemo userinfo={this.state.userinfo}/>
      	                </div>
		);
	}
}

export default App;
// 中层 FluxDemo.jsx
import React from 'react';
import FluxView from './FluxView.jsx';
import PropTypes from 'prop-types';

class FluxDemo extends React.Component {
	constructor(props) {
		super(props);
		this.state = {};
	}
    
        // 另一种定义 childContextTypes 
        //static childContextTypes = {
        //    userinfo: PropTypes.string
        //}
    
        // 读取content的函数
	getChildContext() {
		return {
			userinfo: this.props.userinfo
		};
	}

	render() {
		return(
			<div>
				<FluxView />
      		        </div>
		);
	}
}

// 关键代码
FluxDemo.propTypes = {
	userinfo: PropTypes.string
}

// 关键代码
FluxDemo.childContextTypes = {
	userinfo: PropTypes.string
};

export default FluxDemo;
// 底层
import React from 'react';
import PropTypes from 'prop-types';

class FluxView extends React.Component {
	constructor(props) {
		super(props);
		this.state = {};
	}

	render() {
		return(
			<div>
				{this.context.userinfo}
      		        </div>
		);
	}
}

// 关键代码
FluxView.contextTypes = {
	userinfo: PropTypes.string.isRequired
};

export default FluxView;

PropTypes的常用类型有:

 PropTypes.array,
 PropTypes.bool,
 PropTypes.func,
 PropTypes.number,
 PropTypes.object,
 PropTypes.string,
 PropTypes.symbol,

 // 任何东西都可以被渲染:numbers, strings, elements,或者是包含这些类型的数组(或者是片段)。
 PropTypes.node,
 
 // 一个 React 元素。
 PropTypes.element,

 

转载于:https://my.oschina.net/u/3987720/blog/2962546

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值