美文网首页
06.Redux入门

06.Redux入门

作者: 小二的学习日记 | 来源:发表于2020-07-14 11:14 被阅读0次

    Redux概念简述

    image.png

    Redux的工作流程

    image.png

    使用Antd实现TodoList页面布局

    这里,我们新建一个项目
    1.cmd命令行运行
    creat-react-app reduxdemo
    2.根据之前学过的内容,整理项目到最简状态(在01这个文章里)
    3.导入antUI
    npm install antd --save
    4.编写新的TodoList
    这里
    Input
    Button
    List
    这三给组件可以从AntDesign官网里去找使用方法

    //===>src/TodoList.js
    import React, { Component } from 'react'
    import 'antd/dist/antd.css';
    import { Input, Button, List } from 'antd';
    
    const data = [
        'Racing car sprays burning fuel into crowd.',
        'Japanese princess to wed commoner.',
        'Australian walks 100km after outback crash.',
        'Man charged over missing wedding girl.',
        'Los Angeles battles huge wildfires.',
    ];
    
    class TodoList extends Component {
        render() {
            return (
                <div style={{ marginTop: '10px', marginLeft: '10px' }}>
                    <div>
                        <Input placeholder="todo info" style={{ width: '300px', marginRight: '10px' }} />
                        <Button type="primary">提交</Button>
                    </div>
                    <List
                        style={{ marginTop: '10px', width: '300px' }}
                        bordered
                        dataSource={data}
                        renderItem={item => <List.Item>{item}</List.Item>}
                    />
                </div>
            )
        }
    }
    
    export default TodoList
    

    5.导入这个组件到项目

    //===>src/App.js
    import React from 'react';
    import TodoList from './TodoList'
    
    function App() {
      return (
        <div className="App">
          <TodoList />
        </div>
      );
    }
    
    export default App;
    
    效果

    创建redux中的store

    1.我们先创建reducer.js文件,defaultState定义要存储的数据对象,并传给state。
    2.接着,我们把存数据的reducer,传给store。后面我们就可以从store里面取数据了
    3.在TodoList文件中,通过store.getState()拿到store,就可以使用store的内容了。
    1.安装redux
    cnpm install --save redux
    2.创建reducer.js

    //===>src/store/reducer.js
    const defaultState = {
        inputValue: '123',
        list: [1, 2]
    }
    export default (state = defaultState, action) => {
        return state;
    }
    

    3.创建store

    //===>src/store/index.js
    import { createStore } from 'redux'
    import reducer from './reducer'
    
    const store = createStore(reducer);
    
    export default store;
    

    4.在TodoList组件中,使用redux

    import React, { Component } from 'react'
    import 'antd/dist/antd.css';
    import { Input, Button, List } from 'antd';
    import store from './store/index.js'
    
    class TodoList extends Component {
    
        constructor(props) {
            super(props);
            this.state = store.getState()
        }
    
        render() {
            return (
                <div style={{ marginTop: '10px', marginLeft: '10px' }}>
                    <div>
                        <Input value={this.state.inputValue} placeholder="todo info" style={{ width: '300px', marginRight: '10px' }} />
                        <Button type="primary">提交</Button>
                    </div>
                    <List
                        style={{ marginTop: '10px', width: '300px' }}
                        bordered
                        dataSource={this.state.list}
                        renderItem={item => <List.Item>{item}</List.Item>}
                    />
                </div>
            )
        }
    }
    
    export default TodoList
    
    效果

    Action和Reducer的编写

    1.为了更好的研究redux,我们需要在浏览器安装redux-devtools-extension这个插件(需要科学上网)。然后按照文档提示,我们在store文件中添加这样一句话:

    //===>src/store/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;
    

    2.回忆一下这个图。我们现在要编写的功能是,在输入框输入内容(蓝色),然后点击确定,组件触发store的dispatch发送action(黄色)。store调用dispatch方法,将action发送给了store(橙色),store不能处理数据,所以他去找reducer仓库(紫色)修改数据。reducer通过传过来的action生成了新的state,return给store。最后store真正的拿到了新的数据,并会触发组件内容的改变。


    回忆

    下面我们实现这个过程。
    3.修改TodoList

    //===>src/TodoList.js
    import React, { Component } from 'react'
    import 'antd/dist/antd.css';
    import { Input, Button, List } from 'antd';
    import store from './store/index.js'
    
    
    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)
        }
    
        render() {
            return (
                <div style={{ marginTop: '10px', marginLeft: '10px' }}>
                    <div>
                        <Input
                            value={this.state.inputValue}
                            placeholder="todo info"
                            style={{ width: '300px', marginRight: '10px' }}
                            onChange={this.handleInputChange} />
                        <Button type="primary" onClick={this.handleBtnClick}>提交</Button>
                    </div>
                    <List
                        style={{ marginTop: '10px', width: '300px' }}
                        bordered
                        dataSource={this.state.list}
                        renderItem={item => <List.Item>{item}</List.Item>}
                    />
                </div>
            )
        }
    
        handleInputChange(e) {
            const action = {
                type: 'change_input_value',
                value: e.target.value
            }
            store.dispatch(action)
        }
    
        handleStoreChange(e) {
            this.setState(store.getState())
        }
    
        handleBtnClick(e) {
            const action = {
                type: 'add_todo_item'
            }
            store.dispatch(action)
        }
    }
    
    export default TodoList
    

    4.修改reducer

    //===>src/store/reducer.js
    const defaultState = {
        inputValue: '123',
        list: [1, 2]
    }
    
    // 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 === 'add_todo_item') {
            const newState = JSON.parse(JSON.stringify(state))
            newState.list.push(newState.inputValue)
            newState.inputValue = ''
            return newState
        }
        return state;
    }
    
    我们配合插件看下效果

    使用Redux完成TodoList删除功能

    1.给List.Item添加点击事件

    //===>src/TodoList.js
    ...
    class TodoList extends Component {
    
        constructor(props) {
           ...
        }
    
        render() {
            return (
                <div style={{ marginTop: '10px', marginLeft: '10px' }}>
                    ...
                    <List
                        style={{ marginTop: '10px', width: '300px' }}
                        bordered
                        dataSource={this.state.list}
                        renderItem={(item, index) => <List.Item onClick={this.handleItemDelete.bind(this, index)}>{item}</List.Item>}
                    />
                </div>
            )
        }
    ...
        handleItemDelete(index) {
            const action = {
                type: 'delete_todo_item',
                index
            }
            store.dispatch(action)
        }
    }
    
    export default TodoList
    

    2.添加reducer中的删除逻辑

    //===>src/store/reducer.js
    const defaultState = {
        inputValue: '',
        list: []
    }
    
    // reducer可以接收state,但是绝不能修改state
    export default (state = defaultState, action) => {
    ...
        if (action.type === 'delete_todo_item') {
            const newState = JSON.parse(JSON.stringify(state))
            newState.list.splice(action.index, 1)
            return newState
        }
        return state;
    }
    
    image.png

    ActionTypes的拆分

    在这个例子中 我们要把change_input_value、add_todo_item、delete_todo_item这些action弄成全局的。
    1.编写actionTypes文件

    //===>src/store/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';
    

    2.修改TodoList.js

    //===>src/TodoList.js
    ...
    import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './store/actionTypes'
    
    class TodoList extends Component {
    ...
        handleInputChange(e) {
            const action = {
                type: CHANGE_INPUT_VALUE,
                value: e.target.value
            }
            store.dispatch(action)
        }
    
        handleStoreChange(e) {
            this.setState(store.getState())
        }
    
        handleBtnClick(e) {
            const action = {
                type: ADD_TODO_ITEM
            }
            store.dispatch(action)
        }
    
        handleItemDelete(index) {
            const action = {
                type: DELETE_TODO_ITEM,
                index
            }
            store.dispatch(action)
        }
    }
    
    export default TodoList
    

    3.修改reducer.js

    //===>src/store/reducer.js
    import { 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 === 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;
    }
    

    使用actionCreator统一创建action

    1.编写actionCreator

    //===>src/store/actionCreators.js
    import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } 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
    })
    

    2.把actionCreator引入TodoList

    //===>src/TodoList.js
    import React, { Component } from 'react'
    import 'antd/dist/antd.css';
    import { Input, Button, List } from 'antd';
    import store from './store/index.js'
    import { getInputChangeAction, getAddItemAction, getDeleteItemAction } from './store/actionCreators'
    
    class TodoList extends Component {
    
        constructor(props) {
            ...
        }
    
        render() {
            return (
               ...
            )
        }
    
        handleInputChange(e) {
            const action = getInputChangeAction(e.target.value)
            store.dispatch(action)
        }
    
        handleStoreChange(e) {
            this.setState(store.getState())
        }
    
        handleBtnClick(e) {
            const action = getAddItemAction()
            store.dispatch(action)
        }
    
        handleItemDelete(index) {
            const action = getDeleteItemAction(index)
            store.dispatch(action)
        }
    }
    
    export default TodoList
    

    Redux知识点复习补充

    纯函数

    纯函数指的是,给定固定的输入,就一定会有固定的输出,而且不会有副作用。
    store是唯一的
    只有store能够改变自己的内容
    Reducer必须是顺函数

    Redux的核心API

    createStore
    store.dispatch
    store.getState
    store.subscribe

    相关文章

      网友评论

          本文标题:06.Redux入门

          本文链接:https://www.haomeiwen.com/subject/kvsgcktx.html