你可能不知道的React用法

前言

React作为前端最的框架之一,但是有的时候我们仅限于能用的阶段,有一些高级用法,我们在日常开发中却很少涉足。但是一旦用起来,我们就能发现它的方便和强大之处,我们就会越来越发现我们已经离不开它了!这就像是刚用React时,我内心是拒绝的,但是现在我已经离不开它了,越来越不能理解以前自己为什么抱着JQuery不放呢!

今天我们重点讲一下Context这个高级API,以及如何封装它,让它更加易用!

Context简介

Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。

在一个典型的 React 应用中,数据是通过props属性由上向下(由父及子)的进行传递的,但这对于某些类型的属性而言是极其繁琐的(例如:地区偏好,UI主题),这是应用程序中许多组件都所需要的。 Context 提供了一种在组件之间共享此类值的方式,而不必通过组件树的每个层级显式地传递 props 。

简单说就是,当你不想在组件树中通过逐层传递props或者state的方式来传递数据时,可以使用Context来实现跨层级的组件数据传递。

假设我们有一种场景,我们有一个业务容器App,里面有一个组件容器Container,Container组件内包含一个Form表单,Form表单里面有一个提交按钮SubmitButton。假如使用props传递,我们就不得不传递四层。
在这里插入图片描述
在这里插入图片描述

看到了吗?很方便吧!这里我们使用Context,在组件可以直接通过context获取最顶层绑定的值,避免了一层层传递props的麻烦,也减少出错的可能性。

如何使用Context

如果要Context发挥作用,需要用到两种组件,一个是Context生产者(Provider),通常是一个父节点,另外是一个Context的消费者(Consumer),通常是一个或者多个子节点。所以Context的使用基于生产者消费者模式。

Context 设计目的是为共享那些被认为对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。例如,在下面的代码中,我们通过一个“theme”属性手动调整一个按钮组件的样式,使用context,我们可以避免通过中间元素传递props。

// 创建一个 theme Context, 默认 theme 的值为 light
const ThemeContext = React.createContext('light');
function ThemedButton(props) {
 // ThemedButton 组件从 context 接收 theme
 return (
 <ThemeContext.Consumer>
 {theme => <Button {...props} theme={theme} />}
 </ThemeContext.Consumer>
 );
}
// 中间组件
function Toolbar(props) {
 return (
 <div>
 <ThemedButton />
 </div>
 );
}
class App extends React.Component {
 render() {
 return (
 <ThemeContext.Provider value="dark">
 <Toolbar />
 </ThemeContext.Provider>
 );
 }
}
复制代码

一种更简单的使用方式

看了上面的使用方式,有没有觉得还是有一些不爽,有没有简单一点的方式呢,或者能不能帮我封装一下呢? 当然可以,Javascript工程师是无所不能的!!!

首先是我们的provider.js,这个就是我们封装的context使用工具

import React, { Component } from 'react';
export const Context = React.createContext();
export class ContextProvider extends Component {
 render() {
 return (
 <Context.Provider value={this.props.context}>
 {this.props.children}
 </Context.Provider>
 );
 }
}
/**
 * 用注解的方式给子组件注入属性
 */
export const injectContext = (contexts) => RealComponent => {
 return class extends Component {
 render() {
 return (
 <Context.Consumer>
 {context => {
 // 将顶层的context分发到各层
 let mapContext = {};
 if(Array.isArray(contexts)) {
 contexts.map(item => {
 mapContext[item] = context[item];
 });
 }
 return (
 <RealComponent {...mapContext} {...this.props} />
 )
 }}
 </Context.Consumer>
 );
 }
 };
};
复制代码

还是举个栗子,来让大家明白上述封装的方法的方便之处。 假如要实现GrandParent -> Parent -> Son,从GrandParent组件传递属性到GrandSon组件,每个组件都有一个独立的文件。

先看入口文件,我们在入口文件进行绑定上下文,使用provider里面的ContextProvider类,这里我们主要绑定了propA和propB。

// 入口文件
import React, { PureComponent } from 'react';
import { ContextProvider } from './provider';
import GrandParent from './GrandParent';
class Index extends PureComponent {
 render () {
 return (
 <ContextProvider context={{
 propA: 'propA',
 propB: 'propB'
 }}>
 <GrandParent />
 </ContextProvider>
 )
 }
}
复制代码

Parent组件没什么特殊的

import React, { PureComponent } from 'react';
import Son from './Son';
class Index extends PureComponent {
 render () {
 return (
 <Son />
 )
 }
}
复制代码

Son组件是真正使用属性propA和propB的地方,我们通过ES6的Decorator实现,非常方便。注入后,可以像props一样使用。

import React, { PureComponent } from 'react';
import { injectContext } from './provider';
import Son from './Son';
@injextContext(['propA', 'propB'])
class Index extends PureComponent {
 render () {
 return (
 <div>
 <span>propA为{this.props.propA}</span>
 <span>propB为{this.props.propB}</span>
 </div>
 )
 }
}
复制代码

后记

在这一小节中,我们主要讲了React的一个高级语法Context,而且为了使用方便,我们封装了ContextProvider类和injextContext方法,使用时利用ES6的Decorator语法糖,非常简便。大家在日常开发中,也可以封装出一些这样的小工具,可以极大提升开发效率。

最后

分享移动开发与微信小程序开发该做哪些!其中有哪些关键的技术点!需要下图学习教程的欢迎加入web前端交流群:854591759获取!
点击链接加入群聊【web前端交流群】:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值