七十九、TodoList示例 深入Redux的工作流

劉潤森!發表於2020-11-20
2020/11/20、 週五、今天又是奮鬥的一天。

@Author:Runsen

React,也有了自己去構建一些應用的信心,那會是一種非常棒的感覺。你學會了管理狀態,一切看起來井井有條。但是,很有可能這就到了你該學習 Redux 的時候了。

Redux-devtools外掛

Redux DevTools是一個開源專案,是為谷歌瀏覽器使用者打造的一款實用除錯外掛,主要適用於開發者使用,使用該外掛可以有效地對應用程式或者網頁的狀態進行除錯操作。

我上傳到CSDN,下載連結:https://download.csdn.net/download/weixin_44510615/13130629

因為我是window系統, 需要新增window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

Redux

原理:React首先改變store裡面的資料state,先要開發一個Aciton,然後通過dispath方法傳遞給store,store再把之前的資料和Action轉化的資料在Reducers進行判斷和對比,Reducers本身就是一個函式,返回新的state,store就替換之前的state。

下面舉新增點選的Redux的工作流流程。

具體程式碼

TodoList.js

import React, {Component } from 'react'
import 'antd/dist/antd.css'
import { Input,Button, List  } from 'antd';
// import store from './store'相當於匯入store/index,js
import store from './store';

class TodoList extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
    this.handleInputChange = this.handleInputChange.bind(this)
    this.handleStoreChange = this.handleStoreChange.bind(this)
    this.handleBtnClick = this.handleBtnClick.bind(this)
    store.subscribe(this.handleStoreChange);
    console.log( this.state)
  }

  render() {
    return(
      <div>
        <div>
          <Input 
          value={this.state.inputValue}
          placeholder="Todo info" 
          style={{width:'300px',marginRight:'10px' }}
          onChange={this.handleInputChange}></Input>
          <Button type="primary"
          onClick={this.handleBtnClick}>提交</Button>
        </div>
        <List
        bordered
        style={{width:'300px',marginTop:'10px' }}
        dataSource={this.state.list}
        renderItem={(item,index) => (
          <List.Item onClick={this.handleItemDelete.bind(this,index)}>
            {item}
          </List.Item>
        )}
        />
      </div>
    )
  }
  
  handleInputChange(e) {
    const action = {
      type: 'change_input_value',
      value: e.target.value
    }
    store.dispatch(action)
  }

  handleStoreChange() {
		this.setState(store.getState());
  }
  
  handleBtnClick() {
    const action = {
      type: 'add_todo_item',
    }
    store.dispatch(action)
  }

  handleItemDelete(index) {
    const action = {
      type: 'delete_todo_item',
      index
    }
    store.dispatch(action)
  }
}

export default TodoList;

reducer.js

/* eslint-disable import/no-anonymous-default-export */
const defaultState = {
  inputValue : '123',
  list: [1,2]

}

export default (state = defaultState , action) => {
  if (action.type === 'change_input_value'){
    const newState = JSON.parse(JSON.stringify(state));
    newState.inputValue = action.value
    return newState
  }

  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 === 'delete_todo_item'){
    const newState = JSON.parse(JSON.stringify(state));
    newState.list.splice(action.inbdex,1)
    return newState
  }

  return state;
}

index.js

import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(
  reducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
  );

export default store;

ActionTypes和ActionCreator拆分

由於全部程式碼在TodoList.js寫死了,不容易維護,需要進行ActionTypes和ActionCreator拆分

具體目錄如下

TodoList.js

import React, {Component } from 'react'
import 'antd/dist/antd.css'
import { Input,Button, List  } from 'antd';
// import store from './store'相當於匯入store/index,js
import store from './store';
import { getInitList, getInputChangeAction, getAddItemAction, getDeleteItemAction } from './store/actionCreators'


class TodoList extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
    this.handleInputChange = this.handleInputChange.bind(this)
    this.handleStoreChange = this.handleStoreChange.bind(this)
    this.handleBtnClick = this.handleBtnClick.bind(this)
    store.subscribe(this.handleStoreChange);
    console.log( this.state)
  }

  render() {
    return(
      <div>
        <div>
          <Input 
          value={this.state.inputValue}
          placeholder="Todo info" 
          style={{width:'300px',marginRight:'10px' }}
          onChange={this.handleInputChange}></Input>
          <Button type="primary"
          onClick={this.handleBtnClick}>提交</Button>
        </div>
        <List
        bordered
        style={{width:'300px',marginTop:'10px' }}
        dataSource={this.state.list}
        renderItem={(item,index) => (
          <List.Item onClick={this.handleItemDelete.bind(this,index)}>
            {item}
          </List.Item>
        )}
        />
      </div>
    )
  }
  
  componentDidMount() {
		const action = getInitList();
		store.dispatch(action);
	}

	handleInputChange(e) {
		const action = getInputChangeAction(e.target.value);
		store.dispatch(action);
	}

	handleStoreChange() {
		this.setState(store.getState());
	}

	handleBtnClick() {
		const action = getAddItemAction();
		store.dispatch(action);
	}

	handleItemDelete(index) {
		const action = getDeleteItemAction(index);
		store.dispatch(action);
	}
}

export default TodoList;

actionCreators.js

import { GET_INIT_LIST, CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION } from './actionTypes';

export const getInputChangeAction = (value) => ({
	type: CHANGE_INPUT_VALUE,
	value
});

export const getAddItemAction = () => ({
	type: ADD_TODO_ITEM
});

export const getDeleteItemAction = (index) => ({
	type: DELETE_TODO_ITEM,
	index
});

export const initListAction = (data) => ({
	type: INIT_LIST_ACTION,
	data
});

export const getInitList = () => ({
	type: GET_INIT_LIST
});

actionTypes.js

export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_ITEM = 'add_todo_item';
export const DELETE_TODO_ITEM = 'delete_todo_item';
export const INIT_LIST_ACTION = 'init_list_action';
export const GET_INIT_LIST = 'get_init_list';

reducer.js

import { INIT_LIST_ACTION, CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes'

const defaultState = {
	inputValue: '',
	list: []
}

// reducer 可以接受state,但是絕不能修改state
// 純函式指的是,給定固定的輸入,就一定會有固定的輸出,而且不會有任何副作用
export default (state = defaultState, action) => {

	if (action.type === CHANGE_INPUT_VALUE) {
		const newState = JSON.parse(JSON.stringify(state));
		newState.inputValue = action.value;
		return newState;
	}

	if (action.type === INIT_LIST_ACTION) {
		const newState = JSON.parse(JSON.stringify(state));
		newState.list = action.data;
		return newState;
	}

	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 === DELETE_TODO_ITEM) {
		const newState = JSON.parse(JSON.stringify(state));
		newState.list.splice(action.index, 1);
		return newState;
	}
	return state;
}

相關文章