Redux基礎概念
????在了解Redux之前首先思考一個問題:為什么要使用Redux?
????React是一個輕量級的視圖層框架,組件之間的通信方式是這樣的:【學習筆記 】React ② 組件拆分以及組件間通信
- 父組件通過屬性的形式向子組件傳遞數據,既可以傳遞數據又可以傳遞方法;子組件通過this.props中接收傳遞過來的方法和數據
- 子組件調用父組件的方法,修改父組件的內容子組件通過
this.props.func()
就可以調用父組件的方法,父組件傳遞的函數this
指向要做綁定,借助這個方法對父組件的數據進行修改
????當我們在實現一些簡單項目的時候,是沒有任何問題的。但是如果開發發型復雜項目,組件之間的通信就會變得復雜,產生許多不利維護的代碼。上面的圖可以形象的表現出引入Redux的優勢,把數據放在store進行管理,一個組件改變了store里面的數據,其他組件就會感知到這個變化,從而進行渲染。
Redux工作流
????將Redux當作一個圖書管理系統,react components
看成一個借書的用戶,action creators
看作‘要借什么書’這句話,store
看作圖書管理員,reducer
看作是圖書管理員的筆記本。下圖很形象表示出了這一流程。
????components
發出action
,通過store.dispatch()
告知store
。store
則通過與reducer
通信,獲取到newState
。將新的state
傳遞給components
,完成通信。這就是redux的工作流。依照這個工作流,對Todolist工程進行改造。
一、使用Ant Design重新編寫Todolist頁面布局
- 安裝Ant Design
yarn add antd
- 在
Todolist.js
中引入樣式文件以及需要的組件
import React, {Fragment, Component} from 'react';
import TodoItem from './TodoItem'
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
import { Input, Button, List } from 'antd';
import store from './store'
class Todolist extends React.Component{
constructor (props) {
super(props)
}
render() {
// console.log('render')
return (
<Fragment>
<div>
<Input value={this.state.inputValue}
placeholder={'to do info'}
style={{width: '300px', marginRight: '10px'}}
/>
<Button type="primary">提交</Button>
</div>
<List
style={{width: '300px', marginTop: '10px'}}
bordered
dataSource={this.state.list}
renderItem={item => (
<List.Item>{item}</List.Item>
)}
/>
</Fragment>
);
}
}
export default Todolist;
在瀏覽器效果如下:
二、實現Redux Flow
- 安裝 redux
yarn add redux
- createStore
在src
目錄下新建store
文件夾,在該文件夾下新建index.js
文件
// 創建store
import { createStore } from 'redux'
const store = createStore();
export default store
- 創建reducer
在store
文件夾下新建reducer.js
文件
export default (state , action) => {
return state
}
- 將reducer傳遞給createStore
import { createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
// const store = createStore(reducer);
// 增加 window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() 是為了使用Reduce DevTools
export default store
- action 和 reducer 的編寫
????以通過實現Todolist基本功能為例來實現action
和reducer
的編寫。基本功能如下:
(1)在input
文本框中輸入待辦事項
(2)點擊提交按鈕,將待辦事情渲染在頁面上,清空文本框內容
(3)點擊某項待辦事項,可將其刪除
1.在store
中設置基礎數據
const defaultState = {
inputValue: '',
list: []
}
export default (state = defaultState, action) => {
console.log(state, action)
return state
}
2.在Todolist.js
中通過store.getState()
獲取store
中的數據,將inputValue
綁定在input
文本框,并在文本框綁定onChange()
事件
<Input value={this.state.inputValue} placeholder={'to do info'} style={{width: '300px', marginRight: '10px'}} onChange={this.handleInputChange} />
handleInputChange(e) {
const action = {
type: 'change_input_value', // 描述這個action是干嘛的
value: e.target.value
}
store.dispatch(action)
}
3.完成store
和reducer
之間的通信
// reducer 可以接收state,但是絕不能修改state
export default (state = defaultState, action) => {
if (action.type === 'change_input_value') {
// 深拷貝 state
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value
return newState
}
console.log(state, action)
return state
}
????以上就實現了第一個基本功能,store中的值是否隨著input文本框的輸入而改變?我們在瀏覽器中看一下效果,
????我們可以看到state
中的值確實隨著input
文本框中輸入的內容發生改變而改變。后面兩個功能也類似,只需要為Button
和List.Item
綁定對應的事件,按照上面流程修改reducer
即可。
handleBtnClick () {
const action = {
type: 'add_todo_item'
}
store.dispatch(action)
}
handleItemDelete (index) {
const action = {
type: 'del_todo_list_item',
value: index
}
store.dispatch(action)
}
if (action.type === 'add_todo_item') {
const newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue)
newState.inputValue = ''
return newState
}
if (action.type === 'del_todo_list_item') {
const newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.value, 1)
return newState
}
三、actionCreator的統一創建
????以上的代碼雖可以實現ReduxFlow,但是從可維護性,以及前端自動化測試方面體驗都不是很好,因此我們需要將actionCreator
做統一管理。
????在store
文件夾下新建actionTypes.js
和actionCreators.js
,分別管理type
和action
// actionTypes.js
export const CHANGE_INPUT_VALUE = 'change_input_value'
//actionCreators.js
import { CHANGE_INPUT_VALUE } from './actionTypes'
export const getInputChangeAction = (value) => ({
type: CHANGE_INPUT_VALUE,
value
})
// Todolist.js
handleInputChange(e) {
const action = getInputChangeAction(e.target.value)
store.dispatch(action)
}
一些零散的點
redux設計和使用的三項原則
1.store是唯一的
2.只有store能改變自己的內容
3.reducer必須是純函數核心API
1.createStore
2.store.dispatch
3.store.getState
4.store.subscribe
(完)