Demo說明
- 本次 Demo 使用了 antd 呈現樣式,需要透過
npm install antd --save
安裝該元件庫 - 在使用 Redux 之前,需要安裝 redux,可以用
npm install redux --save
安裝
程式碼以及說明
需熟記的圖
結果樣式
程式碼
目錄結構
|-src |-index.js |-TodoList.js |-store |-index.js |-reducer.js
/src/index.js
//渲染頁面 import React from 'react' import ReactDOM from 'react-dom' //引入TodoList元件 import TodoList from './TodoList' ReactDOM.render( <TodoList />, document.getElementById('root') )
/src/TodoList.js
//TodoList元件 import React, { Component } from 'react' //引入store import store from './store/index' //引入antd樣式 import 'antd/dist/antd.css' //按需引入輸入框、按鈕、列表項樣式 import { Input, Button, List } from 'antd' class TodoList extends Component { constructor(props) { super(props); //透過store的getState方法獲取公共資料 this.state = store.getState(); this.handleInputChange = this.handleInputChange.bind(this); this.handleStoreChange = this.handleStoreChange.bind(this); this.handleBtnClick = this.handleBtnClick.bind(this); //只要store發生改變,就立即執行handleStoreChange這個方法 store.subscribe(this.handleStoreChange); } render() { return ( <div style={{marginLeft:'30px', marginTop:'10px'}}> <div> <Input placeholder='TodoList' style={{width:'300px', marginRight:'10px'}} value={this.state.inputValue} onChange={this.handleInputChange} /> <Button type='primary' onClick={this.handleBtnClick} > 提交 </Button> </div> <List bordered style={{marginTop:'10px', width:'500px'}} dataSource={this.state.list} renderItem={ (item, index) => ( <List.Item onClick={this.handleItemDelete.bind(this, index)}> {item} </List.Item> ) } /> </div> ) } handleInputChange(e) { //觸發功能:改變輸入框值 const action = { //將此需求用action表達 type: 'CHANGE_INPUT_VALUE', //type即需求的描述, value: e.target.value //value是要傳給sotre的值 }; store.dispatch(action); //將action傳給store,store會自動將action物件的內容傳給reducer }; handleStoreChange() { //得到新的state值 //用getState方法得到最新的store資料,並通知setState更新 this.setState(store.getState()) }; handleBtnClick() { //觸發功能:增加列表項 const action = { type: 'ADD_LIST' }; store.dispatch(action) //傳給Store }; handleItemDelete(index) { // 觸發功能:刪除列表項 const action = { type: 'DELETE_LIST', value: index } store.dispatch(action) //傳給store } } export default TodoList;
/src/store/index.js
//Store部分 //從redux中引入createStore方法 import { createStore } from 'redux'; //引入Reducer import reducer from './reducer'; const store = createStore( //透過createStore()建立一個公共的資料儲存倉 reducer, // 將reducer部分傳遞給store ); export default store;
/src/store/reducer.js
//Reducer部分 const defaultState = { inputValue: '', list: [1, 2, 3] }; //reducer負責管理整個store中的資料 //reducer裡面必須返回一個函式,引數中的state就是整個store倉庫裡儲存的資料 export default (state = defaultState, action) => { //state先定為defaultState if(action.type === 'changeInputValue') { //若需觸發改變輸入框值的功能 //深複製state const newState = JSON.parse(JSON.stringify(state)); //改變state的輸入框值,即是改變渲染的輸入框值 newState.inputValue = action.value; //由於reducer不能直接修改傳遞過來的state,所以透過newState返回修改的結果 // store會根據newState替換原來的state值 return newState; } if(action.type === 'addTodoItem') { //若需觸發增加列表項的功能 const newState = JSON.parse(JSON.stringify(state)); //深複製state newState.list.push(newState.inputValue); //新增列表項 newState.inputValue = ''; //清空輸入欄 return newState; } if(action.type === 'DELETE_LIST') { //若需觸發刪除列表項的功能 const newState = JSON.parse(JSON.stringify(state)); //深複製state newState.list.splice(action.value, 1); //刪除列表項 return newState; } return state; }
最佳化
- 之前寫 action 的時候,我們會發現諸多不便,比如
type
很容易寫錯之類的,不如將 action 部分拆分出來,這會提高程式碼的質量,步驟如下:
新建檔案:
/src/store/actionTypes.js
:用來單獨儲存 action 的type
/src/store/actionCreators.js
:用來封裝 action 的建立
程式碼:
/src/store/actionTypes.js export const CHANGE_INPUT_VALUE = 'change_input_value'; export const ADD_LIST = 'add_list'; export const DELETE_LIST = 'delete_list';
/src/store/actionCreators.js import { CHANGE_INPUT_VALUE, ADD_LIST, DELETE_LIST } from './actionTypes'; export const changeInputValueAction = (value) => ({ type: CHANGE_INPUT_VALUE, value }); export const addListAction = () => ({ type: ADD_LIST }); export const deleteListAction = (index) => ({ type: DELETE_LIST, index })
那麼,
/src/TodoList.js
可以改為:import React, { Component } from 'react'; import store from './store/index'; import 'antd/dist/antd.css'; import { Input, Button, List } from 'antd'; //引入建立的 action import { changeInputValueAction, addListAction, deleteListAction } from './store/actionCreators'; class TodoList extends Component { constructor(props) { super(props); this.state = store.getState(); this.handleInputChange = this.handleInputChange.bind(this); this.handleBtnClick = this.handleBtnClick.bind(this); this.handleStoreChange = this.handleStoreChange.bind(this); store.subscribe(this.handleStoreChange); } render() { return ( <div style={{marginLeft:'30px', marginTop:'20px'}}> <div> <Input placeholder='TodoList' style={{width:'300px', marginRight:'10px'}} value={this.state.inputValue} onChange={this.handleInputChange} /> <Button type='primary' onClick={this.handleBtnClick} > 提交 </Button> </div> <List bordered style={{marginTop:'10px', width:'500px'}} dataSource={this.state.list} renderItem={ (item, index) => ( <List.Item onClick={this.handleItemDelete.bind(this, index)}> {item} </List.Item> ) } /> </div> ) } handleInputChange(e) { //直接使用 changeInputValueAction,並傳入引數 e.target.value const action = changeInputValueAction(e.target.value); store.dispatch(action); } handleBtnClick() { //直接使用 addListAction 這個 action const action = addListAction(); store.dispatch(action) } handleStoreChange() { this.setState(store.getState()) } handleItemDelete(index) { //直接使用 deleteListAction 這個 action const action = deleteListAction(index); store.dispatch(action) } } export default TodoList;
本作品採用《CC 協議》,轉載必須註明作者和本文連結