什么是 Redux
Redux 是一种 JavaScript 应用程序状态管理工具。在 Redux 中,您的程序状态被存储在一个全局存储区域(称为“Store”)中,这个存储区域存储着所有程序的“状态”。一个组件可以将它自己的状态中的一部分存储到这个 Store 中,然后在将来,这个组件就可以从 Store 中取回这个状态。因此,Redux 可以让您对整个应用程序的状态管理进行更好的控制。同时,Redux 也是 React 技术栈中必不可少的一部分。
Redux 的工作原理
Redux 的工作原理可以概括为 3 个步骤:运行第一次,监听,执行。
运行第一次
首先,Redux 中的 Store 存储区域被创建。这个存储区域被创建为一个纯 JavaScript 对象,并且通常是一个空对象。
const initialState = {}; // 初始化状态
其次,在 Redux 中,可以实现多种中间件,这些中间件可以用来适应各种特定场景。Redux 中最常用的中间件是 redux-thunk
,它允许我们在 Action 声明中进行异步操作。因此,我们需要将 redux-thunk
注入到 Redux 的 applyMiddleware() 中。
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './rootReducer'; const store = createStore(rootReducer, initialState, applyMiddleware(thunk));
现在,我们在创建 Store 的时候,将以上代码传递给 createStore() 方法。现在,您可以将组件的数据存储到 Store 中,这通常是通过 dispatch
方法来完成。通过 dispatch,操作将发送到 Store,这里处理就可以被完成了。
store.dispatch({ type: 'ADD_TODO', payload: 'Learn Redux' });
在这个例子中,{ type: 'ADD_TODO', payload: 'Learn Redux' }
是一个 Redux Action 声明。它指定要添加一条新的代办事项到 Store 中,其负载为“学习Redux”。
监听和更新
一旦您的 Store 中有了数据,Redux 就可以通过调用相关的 Reducer 函数,并传递当前的状态和 Action 声明,来将新状态合并到 Store 中。Reducer 函数返回的新状态将会被更新到 Store 中。
// javascriptcn.com 代码示例 // reducer.js const rootReducer = (state = {}, action) => { switch (action.type) { case 'ADD_TODO': return Object.assign({}, state, { todos: [...state.todos, { text: action.payload }] }); default: return state; } }; export default rootReducer;
在这个例子中,Reducer 函数将添加一个新的 Todo 到 Store 中。
一旦 Store 中的新状态被更新,那么通过订阅 Store 的监听器,会调用可用的回调函数。这是 Redux 中主要的订阅模式,并用于处理数据的变更。在 React 中,这通常是通过侦听 Store 中的更改来“重新绘制”组件的 UI。
let unsubscribe = store.subscribe(() => console.log(store.getState())); // 执行几个操作之后 // 输出:{ todos: [ { text: 'Learn Redux' } ] }
执行
在 Store 的状态被更新后,React 可以通过调用存储在 Store 中的新状态来重新渲染 UI。这是整个 Redux 工作原理的最后一步。
Redux 常见问题的解决方案
如何处理异步操作
Redux 是一个同步状态管理工具。但是当应用程序具有复杂的异步逻辑时,Redux 的同步性就可能导致问题。为了解决这个问题,我们可以使用 redux-thunk
或 redux-saga
中间件来对 Action 声明进行异步操作。
例如,在使用 Redux 与 API 一起构建应用程序时,可以使用 fetch
方法来获取数据。如下所示:
// javascriptcn.com 代码示例 import fetch from 'isomorphic-fetch'; export const RECEIVE_POSTS = 'RECEIVE_POSTS'; function receivePosts(posts) { return { type: RECEIVE_POSTS, posts }; } export const REQUEST_POSTS = 'REQUEST_POSTS'; function requestPosts(subreddit) { return { type: REQUEST_POSTS, subreddit }; } export function fetchPosts(subreddit) { return function(dispatch) { dispatch(requestPosts(subreddit)); return fetch(`http://www.reddit.com/r/${subreddit}.json`) .then(response => response.json()) .then(json => dispatch(receivePosts(json.data.children.map(child => child.data)))); }; }
在这个例子中,使用 fetchPosts
方法的 dispatch
函数来执行异步操作。通过此操作,我们将获取一个包含 Reddit 帖子数据的 JSON 对象。一旦操作成功,然后我们使用 dispatch
来触发异步操作的回调函数。这个方法允许在异步操作完成后再次回调执行。
如何处理大量数据或缓存数据
在处理大量数据或缓存数据时,Redux 中的 Immutable.js 库可以为我们提供帮助。Immutable.js 包含可持续的数据结构,它们需要使用不可变的 API 进行管理。这极大地优化了整个应用程序的性能,缓存和数据更新。Immutable.js 可以在 Redux 中与普通的 JavaScript 对象和数组相结合使用,并且对于 JavaScript 代码来说,只是添加了一些新的操作符。
例如,使用 Immutable.js 可以轻松处理 Store 内的大量数据,而无需考虑进行深度比较的成本。
import Immutable from 'immutable'; const myState = Immutable.Map({ foo: 'bar' });
在这个例子中,我们实例化了一个新的 Immutable.Map
对象。这是一个更“透明”的对象,并且稍后可以更高效地转换成相应的 JavaScript 对象。
如何区分容器组件和展示组件
在 Redux 和 React 中,容器组件和展示组件是两个不同的概念。展示组件被设计用于渲染 UI,而容器组件是连接 Store 和展示组件的中间层。容器组件可以将 State 和 Dispatch(Action 声明)传递给展示组件,从而获得对 Store 中的状态和其他操作的更多控制。
例如,在下面的代码片段中,App.js 是一个展示组件,该组件已经连接到 Store,并从 Store 中接收到 Todos 列表。由于 addTodo()
方法在 Store 中声明,因此还需要将该方法绑定到 UI 动作。
// javascriptcn.com 代码示例 import React, { Component } from 'react'; import { connect } from 'react-redux'; import { addTodo } from './actions'; class App extends Component { constructor(props) { super(props); this.handleAddTodo = this.handleAddTodo.bind(this); } handleAddTodo() { this.props.dispatch(addTodo(this.input.value)); this.input.value = ''; } render() { return ( <div> <input ref={node => (this.input = node)} /> <button onClick={this.handleAddTodo}>Add Todo</button> <ul> {this.props.todos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> </div> ); } } const mapStateToProps = state => ({ todos: state.todos }); export default connect(mapStateToProps)(App);
在这个例子中,使用 connect()
方法将 Store 中的状态传递给容器组件。在 handleAddTodo()
方法中,我们调用 addTodo()
函数,并将该方法绑定到 UI 操作中。由于 Store 中的功能是独立的,因此我们可以定义其在 Store 中的行为,并且我们可以在 UI 操作中重用这些功能。
总结
Redux 是 React 技术栈中必不可少的一部分,特别是在处理大量数据或缓存数据时。本文中,我们详细介绍了 Redux 的工作原理,以及解决 Redux 中常见问题的解决方案。如果您正在尝试使用 Redux 构建应用程序,您现在应该了解 Redux 的工作原理,并且知道如何解决其中的常见问题。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653f0e6f7d4982a6eb88e61e