Redux学习2

目录

1.UI组件(渲染)和容器组件(逻辑)的拆分

2.无状态组件

3.Redux中发送异步请求获取数据

4.使用Redux-thunk中间件进行ajax请求发送

5.什么时Redux中间件

6.Redux-saga中间件的使用


1.UI组件(渲染)和容器组件(逻辑)的拆分

将 TodoList.js 拆分成 容器组件TodoList.js 和 UI组件TodoListUI.js 。

(1)TodoList.js

import React, {Component} from 'react';
import 'antd/dist/antd.css';
import ToDoListUI from './TodoListUI';
import store from './store/index';
import {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.handleButtonClick = this.handleButtonClick.bind(this);
        this.handleItemDelete = this.handleItemDelete.bind(this);
        store.subscribe(this.handleStoreChange)  //store中数据改变后执行的方法
    }

    render() {
        return <ToDoListUI inputValue={this.state.inputValue} list={this.state.list}
                           handleInputChange = {this.handleInputChange}
                           handleButtonClick={this.handleButtonClick}
                           handleItemDelete={this.handleItemDelete}/>
    }

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

    handleStoreChange(){
        this.setState(store.getState());  //执行setState后,页面才会重新渲染
    }

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

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

export default TodoList;

 (2)TodoListUI.js

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

class TodoListUI extends Component{
    render(){
        return (
            <div style={{marginTop: 10, marginLeft: 10}}>
                <div>
                    <Input value={this.props.inputValue}
                           placeholder="todo info"
                           style={{width: 300, marginRight: '10px'}}
                           onChange={this.props.handleInputChange}/>
                    <Button type="primary" onClick={this.props.handleButtonClick}>提交</Button>
                    <List style={{marginTop: 10, width: 300}}
                          bordered
                          dataSource={this.props.list}
                          renderItem={(item,index) => (
                              <List.Item onClick={(index)=>{this.props.handleItemDelete(index)}}>{item}</List.Item>
                          )}
                    />
                </div>
            </div>
        )
    }
}

export default TodoListUI;

2.无状态组件

(当一个组件内只有render()函数的时候,我们可以使用无状态组件替换之前的普通组件)

普通组件中包含render等生命周期函数,消耗性能;而无状态组件就是一个函数,因此性能高。

将上面的 UI组件TodoListUI.js 替换 为下面的无状态组件TodoListUI.js:

注:无状态组件(就是一个函数),需要接收容器组件传递来的参数props。

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

const TodoListUI = (props)=>{
    return (
        <div style={{marginTop: 10, marginLeft: 10}}>
            <div>
                <Input value={props.inputValue}
                       placeholder="todo info"
                       style={{width: 300, marginRight: '10px'}}
                       onChange={props.handleInputChange}/>
                <Button type="primary" onClick={props.handleButtonClick}>提交</Button>
                <List style={{marginTop: 10, width: 300}}
                      bordered
                      dataSource={props.list}
                      renderItem={(item,index) => (
                          <List.Item onClick={()=>{props.handleItemDelete(index)}}>{item}</List.Item>
                            //注意!!!外面加了个箭头函数
                      )}
                />
            </div>
        </div>
    )
};

export default TodoListUI;

3.Redux中发送异步请求获取数据

(与react中的ajax请求类似,只不过是通过Redux Flow流程进行)

4.使用Redux-thunk中间件进行ajax请求发送

(1)安装redux-thunk中间件:npm install redux-thunk

(2)创建store时,使用thunk中间件(同时使用devtools开发者工具)

文档:https://github.com/zalmoxisus/redux-devtools-extension中的1.2 Advanced store setup。

redux-thunk中间件:使得可以在action中写异步代码。

(3)原理:使用redux-thunk后action可以返回对象,也可以返回函数;因此,可以将ajax异步操作(一个函数方法)整体放到actionCreator中当做一个action进行创建,并将action返回,再按照Redux流程继续执行。

但store接受的action只能是对象,当store检测到action是一个函数时,会自动的执行该函数。该函数首先进行ajax获取数据,然后改变store中的数据(遵循redux流程,创建action,dispatch(action)。)

()建议:开发复杂项目时,最好将异步操作、复杂的业务逻辑,不要放在生命周期函数、组件内,将其拆分到其他地方。比如可以借助redux-thunk将其放到actionCreator中进行管理,或者使用下面的redux-saga放到单独一个文件中。

1.TodoList.js

import {getInputChangeAction, getAddItemAction, getDeleteItemAction, getTodoList} from './store/actionCreators';


componentDidMount() {
        const action = getTodoList();
        store.dispatch(action);  //action动作是一个函数,当处理这个action时,就会执行该函数
    }

 2.actionCreators.js

import axios from "axios";


//没有使用thunk中间件之前,action只能返回对象如上所示,使用thunk后可以返回函数
export const getTodoList = () => {
    return (dispatch)=>{
        axios.get('/list.json').then((res)=>{
            const data=res.data;
            const action = initAjaxListAction(data);
            dispatch(action);
        })
    }
};

5.什么时Redux中间件

Redux流程:

  1. view组件派发action;
  2. action通过store的dispatch方法派发给store;
  3. store接收到action连同之前的state传给Reducer;
  4. Reducer处理后返回新的数据给store;
  5. store根据新数据改变自己的state。

中间件:action派发给store,使用的就是store的dispatch方法;当使用中间件之后,派发的action从只能是对象升级为可以是对象或函数了,因此中间件改变的就是dispatch方法,所以中间件就是对dispatch方法的一个升级(封装)。

中间件是在创建store时设置的。

设置redux-thunk中间件后:

  • 如果action是一个对象,调用dispatch方法时,直接将action对象派发给store。
  • 如果action是一个函数,调用dispatch方法时,先执行该函数,执行完后,若需要向store派发action对象时,再进行派发action。

中间件在action、store之间,所以是Redux的中间件;中间件有很多,功能不同;

redux-thunk:将异步操作放在action中,action可以是函数

6.Redux-saga中间件的使用

文档:https://github.com/redux-saga/redux-saga

redux-saga:将异步代码拆分到单独的一个sagas.js文件中(可以完全替代redux-thunk)

使用saga后,ActionCreator派发action后,不仅reducer.js可以接收到action,sagas.js也能捕获到action,因此,在sagas文件中可以根据action中传递的类型进行相应的异步操作(与Reducer中进行操作类似)。

流程:

  1. 安装redux-saga:npm install --save redux-saga
  2. 创建store时,配置redux-saga(官方文档)
  3. 创建sagas.js文件(其中一定要导出一个generator函数)

(1)TodoList.js

import { getInputChangeAction, getAddItemAction, getDeleteItemAction, getInitList} from './store/actionCreators';


componentDidMount() {
        const action =getInitList();  //ajax请求是异步的,所以使用redux-saga中间件
        store.dispatch(action);
    }

(2)store / index.js(创建store,配置中间件)

import {createStore, applyMiddleware, compose} from "redux";
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga';
import todoSagas from './sagas';

// create the saga middleware
const sagaMiddleware = createSagaMiddleware()

const composeEnhancers =
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(
    applyMiddleware(sagaMiddleware)
);
const store = createStore(reducer, enhancer);  //创建store时,使用redux的两个中间件
// then run the saga
sagaMiddleware.run(todoSagas);

export default store;

(3)store / actionTypes.js

export const GET_INIT_LIST = 'get_init_list';

(4)store / actionCreators.js

export const initAjaxListAction= (data) => ({
    type: INIT_LIST_ITEM,
    data
});

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

(5)store / sagas.js

import { put, takeEvery } from 'redux-saga/effects';
import {GET_INIT_LIST} from './actionTypes';
import axios from "axios";
import {initAjaxListAction} from './actionCreators'

//进行ajax异步请求数据,并写入list中(同样遵循Redux Flow)。
function* getInitList(){
    try{
        const res = yield axios.get('/list.json');
        const action = initAjaxListAction(res.data);
        yield put(action);
    }catch(e){
        console.log('list.json网络请求失败');
    }
};

//ES6中的generator函数
function* mySaga() {
    yield takeEvery(GET_INIT_LIST, getInitList);  //不仅reducer.js能就收到action,这里也能捕获到action
    //接收到GET_INIT_LIST类型的action后,就执行getInitList方法
}

export default mySaga;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值