【學習筆記 】React?⑥ Redux工作流

Redux基礎概念

????在了解Redux之前首先思考一個問題:為什么要使用Redux?
????React是一個輕量級的視圖層框架,組件之間的通信方式是這樣的:【學習筆記 】React ② 組件拆分以及組件間通信

  • 父組件通過屬性的形式向子組件傳遞數據,既可以傳遞數據又可以傳遞方法;子組件通過this.props中接收傳遞過來的方法和數據
  • 子組件調用父組件的方法,修改父組件的內容子組件通過this.props.func()就可以調用父組件的方法,父組件傳遞的函數this指向要做綁定,借助這個方法對父組件的數據進行修改
store.png

????當我們在實現一些簡單項目的時候,是沒有任何問題的。但是如果開發發型復雜項目,組件之間的通信就會變得復雜,產生許多不利維護的代碼。上面的圖可以形象的表現出引入Redux的優勢,把數據放在store進行管理,一個組件改變了store里面的數據,其他組件就會感知到這個變化,從而進行渲染。

Redux工作流

????將Redux當作一個圖書管理系統,react components看成一個借書的用戶,action creators看作‘要借什么書’這句話,store看作圖書管理員,reducer看作是圖書管理員的筆記本。下圖很形象表示出了這一流程。

reduxFlow.png

????components發出action,通過store.dispatch()告知storestore則通過與reducer通信,獲取到newState。將新的state傳遞給components,完成通信。這就是redux的工作流。依照這個工作流,對Todolist工程進行改造。

一、使用Ant Design重新編寫Todolist頁面布局

官方文檔:https://ant.design/docs/react/introduce-cn

  • 安裝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;

在瀏覽器效果如下:


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基本功能為例來實現actionreducer的編寫。基本功能如下:
    (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.完成storereducer之間的通信

// 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文本框的輸入而改變?我們在瀏覽器中看一下效果,


redux-input.gif

????我們可以看到state中的值確實隨著input文本框中輸入的內容發生改變而改變。后面兩個功能也類似,只需要為ButtonList.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.jsactionCreators.js,分別管理typeaction

// 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

項目完整代碼地址:https://github.com/cindygogogo/studyReact

(完)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容