Redux基礎(chǔ)概念
????在了解Redux之前首先思考一個問題:為什么要使用Redux弱贼?
????React是一個輕量級的視圖層框架兜辞,組件之間的通信方式是這樣的:【學(xué)習(xí)筆記 】React ② 組件拆分以及組件間通信
- 父組件通過屬性的形式向子組件傳遞數(shù)據(jù)兑徘,既可以傳遞數(shù)據(jù)又可以傳遞方法贞瞒;子組件通過this.props中接收傳遞過來的方法和數(shù)據(jù)
- 子組件調(diào)用父組件的方法叼旋,修改父組件的內(nèi)容子組件通過
this.props.func()
就可以調(diào)用父組件的方法刃麸,父組件傳遞的函數(shù)this
指向要做綁定阎抒,借助這個方法對父組件的數(shù)據(jù)進行修改
????當我們在實現(xiàn)一些簡單項目的時候酪我,是沒有任何問題的。但是如果開發(fā)發(fā)型復(fù)雜項目且叁,組件之間的通信就會變得復(fù)雜都哭,產(chǎn)生許多不利維護的代碼。上面的圖可以形象的表現(xiàn)出引入Redux的優(yōu)勢逞带,把數(shù)據(jù)放在store進行管理欺矫,一個組件改變了store里面的數(shù)據(jù),其他組件就會感知到這個變化展氓,從而進行渲染穆趴。
Redux工作流
????將Redux當作一個圖書管理系統(tǒng),react components
看成一個借書的用戶遇汞,action creators
看作‘要借什么書’這句話未妹,store
看作圖書管理員,reducer
看作是圖書管理員的筆記本空入。下圖很形象表示出了這一流程络它。
????components
發(fā)出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;
在瀏覽器效果如下:
二、實現(xiàn)Redux Flow
- 安裝 redux
yarn add redux
- createStore
在src
目錄下新建store
文件夾却盘,在該文件夾下新建index.js
文件
// 創(chuàng)建store
import { createStore } from 'redux'
const store = createStore();
export default store
- 創(chuàng)建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 的編寫
????以通過實現(xiàn)Todolist基本功能為例來實現(xiàn)action
和reducer
的編寫∠彼基本功能如下:
(1)在input
文本框中輸入待辦事項
(2)點擊提交按鈕黄橘,將待辦事情渲染在頁面上,清空文本框內(nèi)容
(3)點擊某項待辦事項屈溉,可將其刪除
1.在store
中設(shè)置基礎(chǔ)數(shù)據(jù)
const defaultState = {
inputValue: '',
list: []
}
export default (state = defaultState, action) => {
console.log(state, action)
return state
}
2.在Todolist.js
中通過store.getState()
獲取store
中的數(shù)據(jù)塞关,將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
}
????以上就實現(xiàn)了第一個基本功能帆赢,store中的值是否隨著input文本框的輸入而改變?我們在瀏覽器中看一下效果线梗,
????我們可以看到state
中的值確實隨著input
文本框中輸入的內(nèi)容發(fā)生改變而改變椰于。后面兩個功能也類似,只需要為Button
和List.Item
綁定對應(yīng)的事件仪搔,按照上面流程修改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的統(tǒng)一創(chuàng)建
????以上的代碼雖可以實現(xiàn)ReduxFlow烤咧,但是從可維護性偏陪,以及前端自動化測試方面體驗都不是很好,因此我們需要將actionCreator
做統(tǒng)一管理煮嫌。
????在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設(shè)計和使用的三項原則
1.store是唯一的
2.只有store能改變自己的內(nèi)容
3.reducer必須是純函數(shù)核心API
1.createStore
2.store.dispatch
3.store.getState
4.store.subscribe
(完)