使用 React Hooks 简化 Redux 绑定
介绍
在本指南中,我们将探讨React Hooks的概念,以及它如何与 Redux 结合使用,让我们的生活更轻松。最近,React 已将重点转向功能组件,远离基于类的组件。现在我们不愿意使用功能组件,因为我们知道,如果我们需要在稍后阶段利用组件的生命周期方法或状态管理,我们需要将其转换为类组件。但随着 React Hooks 的引入,适应基于功能的组件变得微不足道。Redux 也引入了Hooks API。
本指南是决定何时将组件连接到 Redux Store 的延续。本指南的主要目标是:
React Hooks 简介
Redux Hooks 简介
使用 ToDo++ 示例探索 Hooks 如何简化状态管理过程。
React Hooks
Hooks 可让您重用状态逻辑,而无需更改组件层次结构。它们让您无需编写类即可使用状态和其他 React 功能。
Hooks 是 Javascript 函数。它们为函数组件提供了一种机制,使其无需依赖包装器组件或高阶组件即可访问状态和生命周期方法。从更大角度来看,这极大地有助于保持组件小巧整洁,并保持相关状态逻辑井然有序。官方文档提供了有关Hooks 的出色概述,但我们将探讨其中的一些关键方面。
Hooks 旨在与功能组件一起使用。React 有一组内置的 Hooks,可用于管理组件的状态逻辑。它们是:
使用State()
使用效果()
useState()使我们能够访问和维护组件的本地状态。对于类组件,我们使用state属性和setState()函数来实现此目的。相比之下,Hooks 提供了更简单的 API 来提供相同的功能。下面的代码展示了使用类组件实现的简单计数器以及使用 Hooks 将其转换为功能组件。
import React, { Component } from 'react';
export default class CounterComponent extends Component{
constructor(props){
super(props);
this.state = {
counter: 0,
someDemoObject: {
someProperty: ""
}
}
}
handleButtonClick = (e) => {
this.setState({
counter: this.state.counter + 1
});
}
render(){
return (
<div>
<div>
{this.state.counter}
</div>
<div>
<button onClick={this.handleButtonClick}>UP YOU GO</button>
</div>
</div>
)
}
}
import React, { useState } from 'react';
export default function CounterComponent(){
const [counter, setCounter] = useState(0);
const [someObject, setObject] = useState({
someProperty: ""
});
return (
<div>
<div>
{counter}
</div>
<div>
<button onClick={() => setCounter(counter+1)}>
UP YOU GO
</button>
</div>
</div>
)
}
如您所见,带有函数的代码简单而干净。另外,需要注意的一件重要事情是,您使用useState函数的参数来传递变量的初始状态。例如,counter的初始状态为0,并将其作为参数传递给函数。您可以根据需要多次使用useState来初始化状态。
这很简洁,但生命周期方法会发生什么?作为 React 开发人员,我们擅长使用componentDidMount()、componentDidUpdate()和componentWillUnmount()方法来管理组件所需的初始 API 调用。例如,如果我们需要在组件安装时从 API 检索计数器的初始状态,这就是一个问题。useEffect()解决了这个问题。下面的代码扩展了我们之前的 CounterComponent,概述了生命周期方法和useEffect()在功能组件中的使用。
import React, { Component } from 'react';
export default class CounterComponent extends Component{
constructor(props){
super(props);
this.state = {
counter: 0,
someDemoObject: {
someProperty: ""
}
}
}
componentDidMount(){
this.setState({
counter: thiss.apiCall()
})
}
apiCall(){
// assume that this function is an API call that
// retrieves the initial counter value from a distant server
return 10;
}
handleButtonClick = (e) => {
this.setState({
counter: this.state.counter + 1
});
}
render(){
return (
<div>
<div>
{this.state.counter}
</div>
<div>
<button onClick={this.handleButtonClick}>UP YOU GO</button>
</div>
</div>
)
}
}
import React, { useState, useEffect } from 'react';
function apiCall(){
// assume that this function is an API call that
// retrieves the initial counter value from a distant server
return 10;
}
export default function CounterComponent(){
const [counter, setCounter] = useState(0);
const [someObject, setObject] = useState({
someProperty: ""
});
useEffect(() => {
setCounter(apiCall());
}, [])
return (
<div>
<div>
{counter}
</div>
<div>
<button onClick={() => setCounter(counter+1)}>
UP YOU GO
</button>
</div>
</div>
)
}
注意:传递给useEffect()函数的第二个参数[]表示我们只需要在组件加载时运行一次代码。这描述了componentDidMount()的行为。默认情况下,如果任何状态 prop 发生变化, useEffect()将重新渲染。
现在我们已经对 Hooks 有了基本的了解。让我们深入研究 Redux 文档,了解它们通过 Hooks 引入的新 API。
Redux Hooks
尽管我很喜欢 React,但我真正不喜欢的一点是启动和运行 store、reducer 和 action 所需的大量样板代码。虽然 Redux 团队推出了 (Redux Start Kit)[https://redux-starter-kit.js.org/] 来减轻一些麻烦,但将 store 绑定到组件并使用操作仍然很麻烦。
Redux 提供了三个 Hooks 来集成功能组件的绑定。它们是:
- useSelector()
- 使用Dispatch()
- useStore()
useSelector()与useState()类似(从非常高的层次来看,实际 API 有很大不同),并提供对 Redux 存储状态的访问。这意味着我们现在可以从代码中删除庞大的mapStateToProps部分。另一方面,useDispatch()处理将操作分派到 Reducer。这消除了代码中对mapDispatchToProps部分的需要。结合起来,这两个 Hook 大大减少了组件中的代码开销。让我们使用上面相同的 Counter 示例来看一下它们的实际作用。为此,假设计数器现在存储在 Redux 存储中,并且已完成必要的启动。
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { increaseCount } from './actions';
class CounterComponent extends Component{
render(){
return (
<div>
<div>
{this.props.counter}
</div>
<div>
<button onClick={this.props.increaseCount}>UP YOU GO</button>
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
counter: state.counter
}
}
const mapDispatchToProps = {
increaseCount
}
export default connect(mapStateToProps, mapDispatchToProps)(CounterComponent);
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increaseCount } from './actions';
export default function CounterComponent(){
const counter = useSelector(state => state.counter);
const dispatch = useDispatch();
return (
<div>
<div>
{counter}
</div>
<div>
<button onClick={() => dispatch(increaseCount())}>
UP YOU GO
</button>
</div>
</div>
)
}
我们不会在本指南中讨论useStore(),但我建议阅读Redux Hooks的官方文档。
现在,掌握了这些信息,让我们来看看如何在实际应用中使用 Hooks。为此,我们将使用与上一指南中相同的想法。我们将讨论 Hooks 的使用如何改变在复杂组件层次结构中使用绑定背后的概念,并应用这些知识来重构 Todo++。
返回 Todo+
在 Todo++ 中,我们讨论了在复杂的组件层次结构中维护 Redux 绑定的想法。我们开发了最小化 Redux 绑定点以提高代码可维护性的概念。但随着 Hooks 的引入,这个概念被修改了。由于绑定过程现在是无缝的,围绕这个问题的新想法建议组件应该在必要时与 Redux 对话。话虽如此,防止滥用它是开发人员的责任。
在转换我们的 ToDo++ 以使用 Hooks 时,我们将使用以下路径。
将操作移动到相关组件
由于我们不受最小化 Redux 绑定规则的约束,我们现在可以让组件直接分派其相应的操作。例如,CheckBoxComponent现在将分派toggleItem操作,而ButtonComponent将分派printItem和deleteItem操作。
集成 Hooks
我们所有的connect都将被useSelector()和useDispatch()方法取代。这并不意味着层次结构中的每个组件都将连接到 store。例如,只将 TodoListComponent 连接到store(以检索项目列表)仍然更有意义。如果我们尝试连接层次结构下方的任何组件,我们最终会陷入不必要的麻烦。
通过这些修改,ToDo++ 现在完全可以在 Hooks 上运行!查看Github Repo<fo
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~