Redux 学习

97 阅读3分钟

1、Redux 入门

1-1、概念

image.png

image.png

1-2、Redux 的工作流程

image.png

简单理解

流程理解:图书馆

react components :借书的人

action Creatos: 你说的 借什么书 这句话

store: 图书馆管理员

Reducers: 记录本

借书人(react components)说,我要借一本名为围城的书(action creators),给图书馆管理员说(store),图书馆管理员(store)去记录本(reducers)中查找这本书,给借书人(react components);

工作流程详解

1、react 首先去改变store中数据,先要派发一个action,action会通过dispatch方法传递给store;

2、store会把之前的数据和action转发给reducer;

3、reducer是一个函数,接收到action和state之后,会做一些处理之后返回一个新的state给store;

4、store再用新的state替换掉之前的数据;

5、store中的数据发生改变后,react会感知到store中数据改变,然后从store中重新去取数据,更新组件的内容,页面就跟着发生变化;

1-3、Redux 的使用

index.js

import React from 'react';
import store from './store'
import TodoListUI from './TodoListUI'
import {handleInputChange, handleListValue, handleDeleteItem} from './store/actionCreator'

class TodoList2 extends React.Component {
    constructor(props) {
        super(props);
        this.state = store.getState()
        // 订阅store
        store.subscribe(this.handleStoreChange)
    }
    // store中state发生改变
    handleStoreChange = () => {
        this.setState(store.getState())
        console.log('store change')
    }
    handleInputChange = (e) => {
        const action = handleInputChange(e.target.value)
        store.dispatch(action)
    }
    handleClick = () => {
        const action = handleListValue()
        store.dispatch(action)
    }

    iconClick = (index) => {
        const action = handleDeleteItem(index)
        store.dispatch(action)
    }

    componentDidMount() {
        // axios.get('/list.json').then(res => {
        //     console.log(res)
        //     const data = res.data
        //     store.dispatch(data)
        // })
    }

    render() {
        return <TodoListUI
            handleInputChange={this.handleInputChange}
            inputValue={this.state.inputValue}
            handleClick={this.handleClick}
            list={this.state.list}
            iconClick={this.iconClick}
        />
    }
}

export default TodoList2

TodoListUI.js

import React from 'react';
import {Input, List, Button} from "antd";

const TodoListUI = (props) => {
    return (
        <div>
            <Input
                value={props.inputValue}
                onChange={props.handleInputChange}
                style={{marginBottom: '10px', width: '210px', marginRight: '10px'}}/>
            <Button type="primary" onClick={props.handleClick}>submit</Button>
            <List
                style={{width: '300px'}}
                size="large"
                header={<div>Header</div>}
                footer={<div>Footer</div>}
                bordered
                dataSource={props.list}
                renderItem={(item, index) => <List.Item onClick={(index) => props.iconClick(index)}>
                    {item}
                </List.Item>}
            ></List>
        </div>
    )
}

export default TodoListUI

index.js

import {createStore, applyMiddleware} from "redux";
import reducer from './reducer'
import thunk from 'redux-thunk'

const store = createStore(
    reducer,
    applyMiddleware(thunk)
)

export default store

actionType.js拆分

export const DELETE_LIST_ITEM = 'delete_list_item'
export const CHANGE_INPUT_VALUE = 'change_input_value'
export const CHANGE_LIST_VALUE = 'change_list_value'

actionCreator 统一创建 action

import {DELETE_LIST_ITEM, CHANGE_LIST_VALUE, CHANGE_INPUT_VALUE} from './actionTypes'

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

export const handleListValue = () => ({
    type: CHANGE_LIST_VALUE,
})

export const handleDeleteItem = (index) => ({
    type: DELETE_LIST_ITEM,
    index
})

reducer.js

import {DELETE_LIST_ITEM, CHANGE_LIST_VALUE, CHANGE_INPUT_VALUE} from './actionTypes'

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

export default function reducer(state = defaultStore, action) {
    if (action.type === CHANGE_INPUT_VALUE) {
        const newValue = JSON.parse(JSON.stringify(state))
        newValue.inputValue = action.value
        return newValue
    } else if (action.type === CHANGE_LIST_VALUE) {
        const newValue = JSON.parse(JSON.stringify(state))
        newValue.list.push(newValue.inputValue)
        newValue.inputValue = ''
        return newValue
    } else if (action.type === DELETE_LIST_ITEM) {
        const newValue = JSON.parse(JSON.stringify(state))
        newValue.list.splice(action.index, 1)
        return newValue
    }
    return state
}

1-4、Redux 设计和使用的三大原则

image.png

1-5、Redux 中核心API

createStore: 创建store

store.dispatch: 派发action,action会传递给store

store.getState: 可以获取store里面所有的数据内容

store.subscribe: 订阅store的改变,只要store发生改变,store.subscribe接收的回调函数就会被执行

2、Redux 进阶

2-1、Redux-thunk 中间件可以在action中进行ajax异步请求

redux-thunk链接

接口请求写在 componentDidMount()中,代码多的话,显得冗余:

image.png

使用redux-thunk统一管理:通过redux 创建store的时候,可以使用中间件,这个中间件是redux的中间件

image.png

然后就可以在action中进行异步请求:

image.png

2-2、什么是 redux 中间件 ?

中间件指的是:actionstore的中间,所以指的是redux的中间件。 image.png

2-3、 redux-saga 中间件的使用

redux-saga使用链接

没有中间件的时候,ajax异步请求写在生命周期中:

image.png

使用 redux-saga

image.png

image.png

redux-saga中进行异步请求

image.png

2-4、react-redux 的使用

1、 安装: npm install react-redux

2、在main.js 中引入 react-redux,provider的意思: provider里面的所有组件都可以获取store的内容.

image.png

3、 在组件中使用 connect 方法,让当前组件和store进行连接。

mapStateToProps: 把store中的数据(state)映射给组件,变成组件的 props,在组件中用{this.props.inputValue}的方式使用;

mapDispatchToProps: Diapatch => store.dispatch, Props => props

import React, { PureComponent } from 'react';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { LoginWrapper, LoginBox, Input, Button } from './style';
import { actionCreators } from './store';

class Login extends PureComponent {
   render() {
      const { loginStatus } = this.props;
      if (!loginStatus) {
         return (
            <LoginWrapper>
               <LoginBox>
                  <Input placeholder='账号' innerRef={(input) => {this.account = input}}/>
                  <Input placeholder='密码' type='password' innerRef={(input) => {this.password = input}}/>
                  <Button onClick={() => this.props.login(this.account, this.password)}>登陆</Button>
               </LoginBox>
            </LoginWrapper>
         )
      }else {
         return <Redirect to='/'/>
      }
   }
}

const mapState = (state) => ({
   loginStatus: state.getIn(['login', 'login'])
})

const mapDispatch = (dispatch) => ({
   login(accountElem, passwordElem){
      dispatch(actionCreators.login(accountElem.value, passwordElem.value))
   }
})

export default connect(mapState, mapDispatch)(Login);