怎样使用React Context API

时间: 2019-02-20阅读: 1198标签: react

react Context API 现在已经成为一个实验性功能,但是只有在 react 16.3.0 中才能用在生产中。本文将向你展示两个基本的 Web 商店应用程序,一个使用了 Context API 进行构建,另一个则不用。

这个新的API解决了一个严重的问题 ——prop drilling。 即使你不熟悉这个术语,如果你曾经用 React.js 做过开发,它可能就已经在你身上发生过了。 Prop drilling 是通过将数据传递到多个中间 React 组件层,将数据从组件A 获取到组件 Z 的过程。 组件将间接的接收props,而你必须确保一切正常。

我们先探讨如何在没有 React Context API 的情况下处理常见问题:

App.js

class App extends Component {
    state = {
        cars: {
            car001: { name: 'Honda', price: 100 },
            car002: { name: 'BMW', price: 150 },
            car003: { name: 'Mercedes', price: 200 }
        }
    };
    incrementCarPrice = this.incrementCarPrice.bind(this);
    decrementCarPrice = this.decrementCarPrice.bind(this);

    incrementCarPrice(selectedID) {
        // a simple method that manipulates the state
        const cars = Object.assign({}, this.state.cars);
        cars[selectedID].price = cars[selectedID].price + 1;
        this.setState({
            cars
        });
    }

    decrementCarPrice(selectedID) {
        // a simple method that manipulates the state
        const cars = Object.assign({}, this.state.cars);
        cars[selectedID].price = cars[selectedID].price - 1;
        this.setState({
            cars
        });
    }

    render() {
        return (
            <div className="App">
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    <h1 className="App-title">Welcome to my web store</h1>
                </header>
                {/* Pass props twice */}
                <ProductList
                    cars={this.state.cars}
                    incrementCarPrice={this.incrementCarPrice}
                    decrementCarPrice={this.decrementCarPrice}
                />
            </div>
        );
    }
}

ProductList .js

const ProductList = props => (
    <div className="product-list">
        <h2>Product list:</h2>
        {/* Pass props twice */}
        <Cars
            cars={props.cars}
            incrementCarPrice={props.incrementCarPrice}
            decrementCarPrice={props.decrementCarPrice}
        />
        {/* Other potential product categories which we will skip for this demo: */}
        {/* <Electronics /> */}
        {/* <Clothes /> */}
        {/* <Shoes /> */}
    </div>
);

export default ProductList;

Cars.js

const Cars = props => (
    <Fragment>
        <h4>Cars:</h4>
        {/* Finally we can use data */}
        {Object.keys(props.cars).map(carID => (
            <Car
                key={carID}
                name={props.cars[carID].name}
                price={props.cars[carID].price}
                incrementPrice={() => props.incrementCarPrice(carID)}
                decrementPrice={() => props.decrementCarPrice(carID)}
            />
        ))}
    </Fragment>
);

Car.js

const Cars = props => (
    <Fragment>
        <p>Name: {props.name}</p>
        <p>Price: ${props.price}</p>
        <button onClick={props.incrementPrice}>&uarr;</button>
        <button onClick={props.decrementPrice}>&darr;</button>
    </Fragment>
);

当然,这不是处理数据的最好方式,但我希望能够用它说明为什么 prop drilling 很差劲。 那么 Context API 是如何帮我们避免这种情况呢?

介绍Context Web Store

让我们重构程序并演示它可以做些什么。 简而言之,Context API 允许你拥有一个存储数据的中央存储(是的,就像存储在 Redux 中一样)。你可以把任何组件直接插入到商店应用中,也可以切断 middleman!


重构非常简单 —— 我们不必对组件的结构进行任何修改。但是我们确实需要创建一些新组件:Provider 和 consumer。


1.初始化 Context

首先,我们需要创建context,后面可以使用它来创建 Provider 和 consumer。

MyContext.js

import React from 'react';

// this is the equivalent to the createStore method of Redux
// https://redux.js.org/api/createstore

const MyContext = React.createContext();

export default MyContext;


2. 创建 Provider

完成后,我们可以导入 context 并用它来创建我们的 provider,我们称之为 MyProvider。在里面使用一些值初始化一个状态,你可以通过 value prop 共享我们的 provider 组件。 在例子中,我们将共享 this.state.cars 以及一些操纵状态的方法。 将这些方法可以看作是 Redux 中的 Reducer。

MyProvider.js

import MyContext from './MyContext';

class MyProvider extends Component {
    state = {
        cars: {
            car001: { name: 'Honda', price: 100 },
            car002: { name: 'BMW', price: 150 },
            car003: { name: 'Mercedes', price: 200 }
        }
    };

    render() {
        return (
            <MyContext.Provider
                value={{
                    cars: this.state.cars,
                    incrementPrice: selectedID => {
                        const cars = Object.assign({}, this.state.cars);
                        cars[selectedID].price = cars[selectedID].price + 1;
                        this.setState({
                            cars
                        });
                    },
                    decrementPrice: selectedID => {
                        const cars = Object.assign({}, this.state.cars);
                        cars[selectedID].price = cars[selectedID].price - 1;
                        this.setState({
                            cars
                        });
                    }
                }}
            >
                {this.props.children}
            </MyContext.Provider>
        );
    }
}

为了使 provider 可以访问其他组件,我们需要用它包装我们的应用程序(没错,就像 Redux 一样)。我们可以摆脱这些状态和方法,因为它们在 MyProvider.js 中定义。

App.js

class App extends Component {
    render() {
        return (
            <MyProvider>
                <div className="App">
                    <header className="App-header">
                        <img src={logo} className="App-logo" alt="logo" />
                        <h1 className="App-title">Welcome to my web store</h1>
                    </header>
                    <ProductList />
                </div>
            </MyProvider>
        );
    }
}


3. 创建 Consumer

我们需要再次导入 context 并用它包装我们的组件,它会在组件中注入context 参数。 之后,它非常直接。 你使用 context 就像用 props 一样。 它包含我们在 MyProducer 中共享的所有值,我们所需要做的只是去使用它!

Cars.js

const Cars = () => (
    <MyContext.Consumer>
        {context => (
            <Fragment>
                <h4>Cars:</h4>
                {Object.keys(context.cars).map(carID => (
                    <Car
                        key={carID}
                        name={context.cars[carID].name}
                        price={context.cars[carID].price}
                        incrementPrice={() => context.incrementPrice(carID)}
                        decrementPrice={() => context.decrementPrice(carID)}
                    />
                ))}
            </Fragment>
        )}
    </MyContext.Consumer>
);

我们似乎忘记了什么?是 ProductList !它使好处变得非常明显。 我们不必传递任何数据或方法。这个组件被简化,因为它只需要去渲染一些组件。

ProductList.js

const ProductList = () => (
    <div className="product-list">
        <h2>Product list:</h2>
        <Cars />
        {/* Other potential product categories which we will skip for this demo: */}
        {/* <Electronics /> */}
        {/* <Clothes /> */}
        {/* <Shoes /> */}
    </div>
);

在本文中,我对 Redux 和 Context API 进行了一些比较。 Redux 最大的优势之一就是你的应用可以拥有一个可以从任何组件访问的中央存储。而使用新的 Context API,默认情况下你已经有了这个功能。 在巨大的宣传攻势下 Context API 将会使 Redux 变得过时。

对于那些只把 Redux 作为中央存储功能的人来说,可能确实如此。 如果你只使用 Redux 的这一个功能,现在可以使用 Context API 替换它,并避免在不使用第三方库的情况下进行 prop drilling。


翻译:疯狂的技术
原文:https://www.toptal.com/react/... 

 

站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

链接: http://www.fly63.com/article/detial/2066

React组件的state和props

React 的数据是自顶向下单向流动的,即从父组件到子组件中,组件的数据存储在 props 和 state 中。实际上在任何应用中,数据都是必不可少的,我们需要直接的改变页面上一块的区域来使得视图的刷新

React 新 Context API

React 新 Context API它更符合工程化, 不再是实验性的,现在它是一流的API! 并且它还使用了 RENDER PROP!你在react官网上听说过 context API?那么你为何要使用context?Context的重生

渐进式React

可以说 React 为Web开发者带来了全新的开发模式,而在各类新功能下,如何达到性能最优仍是我们需要关心的。今天做一次精读尝试,原文地址在文末,话不多说,先呈上一份性能清单:

React 开发者常见的 3 个错误

关于前端开发,我最开心的事情就是总有新的东西可以学习。但我们可能一辈子都在掌握各种编程语言、库和框架,但仍然一无所知。因为我们都在学习,这也意味着我们都容易犯错误

ReactJS 生命周期、数据流与事件

React是一个JavaScript库文件,使用它的目的在于能够解决构建大的应用和数据的实时变更。该设计使用JSX允许你在构建标签结构时充分利用JavaScript的强大能力,而不必在笨拙的模板语言上浪费时间

如何写出漂亮的 React 组件

在Walmart Labs的产品开发中,我们进行了大量的Code Review工作,这也保证了我有机会从很多优秀的工程师的代码中学习他们的代码风格与样式。在这篇博文里我会分享出我最欣赏的五种组件模式与代码片。不过我首先还是要谈谈为什么我们需要执着于提高代码的阅读体验

react 源码之setState

与multirepo 相对。 monorepo是单代码仓库, 是把所有相关项目都集中在一个代码仓库中,每个module独立发布,每个module都有自己的依赖项(package.json),能够作为独立的npm package发布,只是源码放在一起维护。

如何扩展 Create React App 的 Webpack 配置

Create React App(以下简称 CRA)是创建 React 应用的一个脚手架,它与其他脚手架不同的一个地方就是将一些复杂工具(比如 webpack)的配置封装了起来,让使用者不用关心这些工具的具体配置,从而降低了工具的使用难度。

为什么说React 16是开发者的福音?

就像人们对更新移动应用程序和操作系统感到兴奋一样,开发人员也应该对更新框架感到兴奋。不同框架的新版本具有新特性和开箱即用的技巧。下面是将现有应用程序从 React 15 迁移到 React 16 时应该考虑的一些好特性。

react-router 路由切换动画

因为项目的需求,需要在路由切换的时候,加入一些比较 zb 的视觉效果,所以研究了一下。把这些学习的过程记录下来,以便以后回顾。同时也希望这些内容能够帮助一些跟我一样的菜鸟,让他们少走些坑。可能我对代码的表述不是很到位,希望大家不要介意。机智的你们一定可以看明白。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!