React 入門-redux 和 react-redux
阿新 • • 發佈:2021-01-24
React 將頁面元素拆分成元件,通過組裝展示資料。元件又有**無狀態**和**有狀態**之分,所謂狀態,可以簡單的認為是元件要展示的資料。React 有個特性或者說是限制**單向資料流**,元件的狀態資料只能在元件內部修改,對於其他元件是**只讀的**,想要修改只能通過元件提供的介面回撥。
隨著元件數量的增多,元件間**狀態資料共享**的複雜性也會隨之增加,如果僅使用 React 元件內的 State 可能會導致程式的流程混亂,程式碼難以維護。
原文連結:https://www.chuonye.com/archives/react-redux.html
## 1. 引入 Redux
為什麼這麼說呢,我們來看一個圖:
![redux][1]
原始的 React,當最底層元件需要改變資料時,如果資料在**父元件**,回撥方法層層傳遞即可;如果在**兄弟元件**,那就需要藉助一箇中間元件,當然了也有辦法直接與兄弟元件通訊。可以想象,隨著應用複雜程度的提高,元件間通訊使用的各種直接或間接回調,可能會導致程式碼亂成一團。
此時,**Redux** 就派上用場了,如上圖所示,它把應用的所有**狀態-資料**儲存在一個地方,並稱之為**Store**,元件間不直接通訊,而是把變化的資料推給 Store,需要根據狀態變化重新渲染的元件通過**訂閱** Store 來實現。
**Redux** 在設計與實現時,遵循**三大原則**或者說**規範限制**。
### 1.1 唯一資料來源
整個應用程式的狀態資料僅儲存在**一個 Store** 中,資料就儲存在一個大的物件樹(object tree)中。
### 1.2 只讀的 Store
唯一的 **Store** 也是隻讀的,應用程式**無法直接修改**狀態資料。**Store** 物件本身的 API 非常少,僅有四個方法:
- `getState()` : 獲取當前狀態資料
- `dispatch(action)` : 推送觸發變化
- `subscribe(listener)` : 訂閱資料變化
- `replaceReducer(nextReducer)`
顯而易見,沒有提供設定狀態的方法。其中的 `dispatch(action)` 是唯一改變資料的方法,比如:
```
var action = {
type: 'ADD_USER',
user: {name: 'chuonye.com'}
};
store.dispatch(action);
```
`dispatch` 方法會將 `action` 傳遞給 **Redux**,action 就是一個普通物件,包含觸發的操作型別以及資料。
### 1.3 使用純函式更改資料
**Redux** 接收到 `action` 後,會使用一個**純函式**來處理,這些函式被稱為 **Reducers**:
```
var someReducer = function(state, action) {
...
return state;
}
```
**Reducer** 接收當前的 state 和 action 作為引數,它也不能直接修改原有的資料,而是通過返回一個新的 state 來修改。
總的來說,**Redux** 是一個幫助應用統一管理狀態資料的工具,它遵循**嚴格的單向資料流**(Store 只讀)設計,使得應用的行為變得可預測且容易理解。
![react-redux-stream][2]
## 2. React-Redux
Redux 一般和 React 這類框架搭配使用,為了方便與 React 整合,Redux 官方提供了一個 **react-redux** 繫結庫。**react-redux** 將元件劃分為**容器元件**,**UI元件**和**其他元件**,其中:
- **容器元件**:與 Redux-Store 互動,分派 Action,監聽 state 變化,負責資料管理和業務邏輯
- **UI 元件**:無狀態,負責資料的展示,樣式,排版,資料來源於 **props** 屬性
- **其他元件**:無法明確區分是容器還是 UI 的元件,或者本身比較簡單沒有拆分必要的元件
從整體來看,在使用上,應用程式碼分層設計,結構如下:
![react-redux][3]
我們不妨結合著**資料庫**,來理解下每個層次的意思,從下往上:
- **Store** 可以理解成**資料庫服務**,其中的 **State** 是一個**資料庫**,State 物件樹的各個部分,可以理解為對應不同的**表**
- **Reducer** 就是實際對 State **增刪改**的,它按邏輯拆分成多個 **子reducer**,分別對物件樹的**不同部分**或者說對**不同的表**進行操作,就如同一個 **SQL 執行引擎**
- **Action** 就是一系列觸發改變的動作以及資料,就如同一條條 **SQL 語句**
- 容器元件和 UI 元件就如同 Java 中設計的 DAO 和 Controller
這些設計怎麼有點熟悉,跟 Java 是越來越像了。下面簡單寫個例子,看看到底怎麼用。
## 3. 例項:Counter 計數器
接下來我們按照**使用原生 React**,使用 **Redux** 和使用 **React-Redux**的順序分別實現一個 **Counter** 計數器的功能。
### 3.1 原生 React 實現
```
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Counter extends Component {
constructor(props) {
super(props);
this.state = { value: 0 }; // 狀態資料
}
render() {
return (
state: {this.state.value}
); } // 處理方法 handleIncrement() { let curVal = this.state.value + 1; this.setState({value: curVal}); } handleDecrement() { let curVal = this.state.value - 1; this.setState({value: curVal}); } } // 渲染 ReactDOM