The React Context API 在 React 生态系统中并不是个新鲜事物。不过,在 React 16.3.0 版本中做了一些改进。这些改进是如此巨大,以至于大大减少了我们对 Redux 和其他高级状态管理库的需求。在本文中,你将通过一个实用教程了解到新的 React Context API 是如何取代 Redux 完成小型应用的状态管理的。
在直奔主题之前,我们先来快速回顾下 Redux,以便我们更好的比较两者的区别。redux 是一个便于状态管理的JavaScript库。Redux 本身和 React 并没有关系。来自世界各地的众多开发者选择在流行的前端框架(比如 React 和 angular )中使用 Redux。
说明一点,在本文中,状态管理指的是处理单页面应用(SPA)中产生的基于特定事件而触发的状态变化。比如,一个按钮的点击事件或者一条来自服务器的异步信息等,都可以触发应用状态的变化。
在 Redux 中,你尤其需要注意下面几点:
如果你对 Redux 并不熟悉并且你想要了解更多,请移步 Redux 的实用教程学习。
The React Context API 提供了一种通过组件树传递数据的方法,而不必通过 props 属性一层层的传递。在React中,数据通常会作为一个属性从父组件传递到子组件。
使用最新的 React Context API 取决于三个关键步骤:
如你所见,所涉及的概念实际上与 Redux 没有什么不同。事实上,甚至 Redux 也在其公共API的底层使用了 React Context API。然而,直到最近,Context API 才达到了足够独立使用的水平。
如上所述,本文的目标是向你展示新的 Context API 如何在小型应用中替代 Redux 的。因此,你将首先用 Redux 创建一个简单的 React app,然后,你将学习如何删除这个状态管理库,以便可以使用 React Context API 来再次实现它。
你将构建的示例应用是一个处理一些流行食物及其来源的列表。这个应用还将包括一个搜索功能,使用户能够根据一些关键词过滤列表。
最终,你将创建一个类似下面所述的应用:
由于本文仅使用 React 和一些 npm 库,因此除了 Node.js 和 NPM 之外,你什么都不需要。如果你还没有安装 Node.js 和 NPM,请前往官网下载并安装。
安装这些依赖后,你还需要安装 create-react-app 工具。这个工具帮助开发人员创建 React 项目。打开一个终端并运行以下命令来安装:
npm i -g create-react-app
安装完 create-react-app 后,进入项目所在目录,执行以下命令:
create-react-app redux-vs-context
几秒钟后,create-react-app 将完成应用程序的创建。在此之后,进入该工具创建的新目录,并安装 Redux:
# move into your project
cd redux-vs-context
# install Redux
npm i --save redux react-redux
Note: redux 是主库,react-redux 是促进 React 和 Redux 之间交互的库。简而言之,后者充当 React 和 Redux 之间的代理。
你已经搭建好了你的 React 应用,安装好了 Redux,现在,在你喜欢的开发工具中打开你的项目。然后在 src 文件夹中创建三个文件:
所以,首先,打开 foods.json 文件,添加如下内容:
[
{
"name": "Chinese Rice",
"origin": "China",
"continent": "Asia"
},
{
"name": "Amala",
"origin": "Nigeria",
"continent": "Africa"
},
{
"name": "Banku",
"origin": "Ghana",
"continent": "Africa"
},
{
"name": "Pão de Queijo",
"origin": "Brazil",
"continent": "South America"
},
{
"name": "Ewa Agoyin",
"origin": "Nigeria",
"continent": "Africa"
}
]
正如你所见,json文件存储的数据并没有什么特别的。仅仅是一个包含着不同食物及其来源的数组。
在定义了 foods.json 文件后,你可以专注于创建你的 Redux store 了。回顾一下,store 是保存你的应用中的真实状态的唯一来源。打开你的 reducers.js 文件,并向其中添加以下代码:
import Food from './foods';
const initialState = {
food: Food,
searchTerm: '',
};
export default function reducer(state = initialState, action) {
// switch between the action type
switch (action.type) {
case 'SEARCH_INPUT_CHANGED':
const {searchTerm} = action.payload;
return {
...state,
searchTerm: searchTerm,
food: searchTerm ? Food.filter(
(food) => (food.name.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1)
) : Food,
};
default:
return state;
}
}
在上面的代码中,你可以看到 reducer 方法接收两个参数:state 和 action。当你启动你的 React 应用,这个方法将获得它之前定义的初始状态,当你 dispatch 一个 action 的实例时,这个方法将获得当前状态(不再是初始状态)。然后,基于这些 actions 的内容,reducer 方法将为你的应用程序生成一个新的状态。
接下来,你必须定义这些 actions 做什么。实际上,为了简单起见,你将定义一个单一的 action ,当用户在你的应用中输入搜索词时,这个 action 会被触发。因此,打开 actions.js 文件,并在其中插入以下代码:
function searchTermChanged(searchTerm) {
return {
type: 'SEARCH_INPUT_CHANGED',
payload: {searchTerm},
};
}
export default {
searchTermChanged,
};
action 创建好之后,你需要做的下一件事就是将你的 app 组件包装到 react-redux 提供的 Provider 组件中。Provider 统一负责 React 应用的数据(即 store)传递。
要使用 provider ,首先,你将使用 reducers.js 中定义的 initialState 创建 store。然后,通过 Provider 组件,你将把 store 传给你的 App。要完成这些任务,你必须打开 index.js 文件,并将其内容替换为:
import React from 'react';
import Reactdom from 'react-dom';
import {Provider} from 'react-redux';
import {createStore} from 'redux';
import reducers from './reducers';
import App from './App';
// Creating the store using the reducers info.
// That's because reducers are the building blocks of a Redux Store.
const store = createStore(reducers);
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
);
就是这样!你刚刚在 React 应用中配置完 Redux。现在,你必须实现UI (用户界面),这样你的用户就可以使用本节中实现的功能了。
现在,你已经完成了应用中的核心代码,你可以专注于构建你的用户界面。为此,打开你的 App.js 文件,用下方代码替换它的内容:
import React from 'react';
import {connect} from 'react-redux';
import actions from './actions';
import './App.css';
function App({food, searchTerm, searchTermChanged}) {
return (
<div>
<div className="search">
<input
type="text"
name="search"
placeholder="Search"
value={searchTerm}
onChange={e => searchTermChanged(e.target.value)}
/>
</div>
<table>
<thead>
<tr>
<th>Name</th>
<th>Origin</th>
<th>Continent</th>
</tr>
</thead>
<tbody>
{food.map(theFood => (
<tr key={theFood.name}>
<td>{theFood.name}</td>
<td>{theFood.origin}</td>
<td>{theFood.continent}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default connect(store => store, actions)(App);
对于未用过 Redux 的人来说,他们唯一不熟悉的是用于封装 App 组件的 connect 方法。这个方法实际上是一个高阶组件( HOC ),充当应用程序和Redux之间的粘合剂。
使用以下命令启动你的应用,你将能够在浏览器中访问你的应用:
npm run start
然而,正如你所看到的,这个应用现在很难看。因此,为了让它看起来更好一点,你可以打开 App.css 文件,用以下内容替换它的内容:
table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
line-height: 25px;
}
th {
background-color: #eee;
}
td, th {
text-align: center;
}
td:first-child {
text-align: left;
}
input {
min-width: 300px;
border: 1px solid #999;
border-radius: 2px;
line-height: 25px;
}
完成了!你现在有了一个基本的 React 和 Redux 的应用,可以开始学习如何迁移到 Context API 上了。
在本节,你将要学习如何将你的 Redux 应用迁移到 React Context API上。
幸运的是,你不需要在 Redux 和 the Context API 之间做很多的重构。
作为开始,你必须先从你的应用中移除Redux组件。为此,请打开终端,删除 redux 和 react-redux 库:
npm rm redux react-redux
之后,删除应用中对这些库的引用代码。打开 App.js 删除以下几行:
import {connect} from 'react-redux';
import actions from './actions';
然后,在相同的文件中,用下方的代码替换最后一行(以 export default 开头的那一行):
export default App;
有了这些改变,你可以用 Context API 重写你的应用了。
要将之前的应用从 Redux 驱动的应用转换为使用 Context API,你需要一个 context 来存储应用的数据(该 context 将替换 Redux Store)。此外,你还需要一个 Context.Provider 组件,该组件包含 state、props 和正常的 React 组件生命周期。
为此,你需要在src目录中创建一个 providers.js 文件,并向其中添加以下代码:
import React from 'react';
import Food from './foods';
const DEFAULT_STATE = { allFood: Food, searchTerm: '' };
export const ThemeContext = React.createContext(DEFAULT_STATE);
export default class Provider extends React.Component {
state = DEFAULT_STATE;
searchTermChanged = searchTerm => {
this.setState({searchTerm});
};
render() {
return (
<ThemeContext.Provider value={{
...this.state,
searchTermChanged: this.searchTermChanged,
}}> {this.props.children} </ThemeContext.Provider>);
}
}
上面代码中定义的 Provider 类负责将其他组件封装在 ThemeContext.Provider 中。通过这样做,你可以让这些组件访问应用中的 state 和 searchTermChanged 方法,该方法提供了更改该 state 的方法。
若要稍后在组件树中使用这些值,你需要启动一个 ThemeContext.Consumer 组件。这个组件将需要一个 render 渲染方法,该方法将接收上述值 props 作为参数。
因此,接下来,你需要在src目录中创建一个名为 consumer.js 的文件,并将以下代码写入其中:
import React from 'react';
import {ThemeContext} from './providers';
export default class Consumer extends React.Component {
render() {
const {children} = this.props;
return (
<ThemeContext.Consumer>
{({allFood, searchTerm, searchTermChanged}) => {
const food = searchTerm
? allFood.filter(
food =>
food.name.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1
)
: allFood;
return React.Children.map(children, child =>
React.cloneElement(child, {
food,
searchTerm,
searchTermChanged,
})
);
}}
</ThemeContext.Consumer>
);
}
}
现在,为了完成迁移,你将打开 index.js 文件,并在 render() 函数中,用 Consumer 组件包装 App 组件。此外,你需要将 Consumer 包装在 Provider 组件中。代码如下所示:
import React from 'react';
import ReactDOM from 'react-dom';
import Provider from './providers';
import Consumer from './consumer';
import App from './App';
ReactDOM.render(
<Provider>
<Consumer>
<App />
</Consumer>
</Provider>,
document.getElementById('root')
);
打完收工!你刚刚完成了从 Redux 到 React Context API 的迁移。如果你现在启动你的应用,你会发现整个app运行如常。唯一不同的是,你的应用不再使用 Redux 了。
Redux 是一个高级状态管理库,适合在构建大规模 React 应用时使用。另一方面,The Context API 可以用于字节大小级别数据更改的小规模 React 应用中。通过使用 Context API,你不必像 reducers、actions 等一样编写大量代码,就能完成状态变化的逻辑表现。
如今的 Web 前端已被 React、Vue 和 Angular 三分天下,尽管现在的 jQuery 已不再那么流行,但 jQuery 的设计思想还是非常值得致敬和学习的,特别是 jQuery 的插件化。
受控组件与非受控组件在官网与国内网上的资料都不多,有些人觉得它可有可不有,也不在意。这恰恰显示React的威力,满足不同规模大小的工程需求。
一般在传统模式下,我们构建前端项目很简单。就是下载各种js文件,如JQuery、Echart等,直接放置在html静态文件。Webpack则是JavaScript中比较知名的打包工具。这两个构建工具构成了React应用快速搭建的基础。
Gatsby能快速的使用 React 生态系统来生成静态网站,可以结合React Component、Markdown 和服务端渲染来完成静态网站生成让他更强大。
React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归;具体的三种方式:函数式定义的无状态组件、es5原生方式React.createClass定义的组件、es6形式的extends React.Component定义的组件
React主要思想是通过构建可复用组件来构建用户界面,每个组件都有自己的生命周期,它规定了组件的状态和方法需要在哪个阶段改变和执行。所谓组件就是有限状态机,,表示有限个状态以及在这些状态之间的转移和动作行为的模型。
React 相关的优化:使用 babel-react-optimize 对 React 代码进行优化,检查没有使用的库,去除 import 引用,按需打包所用的类库,比如 lodash 、echarts 等.Webpack 构建打包存在的问题两个方面:构建速度慢,打包后的文件体积过大
这篇文章主要介绍React Router定义路由之后如何传值,有关React和React Router 。react router中页面传值的三种方法:props.params、query、state
react 高阶组件简单的理解是:一个包装了另一个基础组件的组件。高阶组件的两种形式:属性代理(Props Proxy)、反向继承 (Inheritance Inversion)
React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!