React (5) Redux 进阶

1.  UI 组件

  1. render()函数放在另外一个单独的UI.js 文件和动作行为分开
  2. UI 上面所用的数据和函数, 通过父组件传递过来,用 this.props 来接收
  3. UI 组件下面:
import 'antd/dist/antd.css';
import { Input, Button, List } from 'antd';
import React, {Component} from 'react';

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

export default TodoListUI

父组件传递数据

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

 

2.  无状态组件

  1. 当一个普通的组件只有render()函数的时候, 没有业务逻辑的时候它就是一个无状态组件, 类似没有业务逻辑的UI组件
  2. 无状态组件性能比较高, 因为它就是一个js, 一个普通组件既包含一个类还有render(), 性能差别就在这
  3. 下面是一个无状态组件
import 'antd/dist/antd.css';
import { Input, Button, List } from 'antd';
import React from 'react';

const TodoListUI = (props) => {
    return (
        <div style={{ margin: '10px' }}>
            <div>
                <Input value={props.inputValue}
                    style={{ width: '300px', marginRight: '10px' }}
                    onChange={props.handleInputChange}
                />
                <Button type="primary"
                    onClick={props.btnClick}
                >提交</Button>
            </div>
            <List
                bordered
                dataSource={props.list}
                renderItem={(item, index) => (<List.Item onClick={(index) => { props.handledelete(index) }}>{item}</List.Item>)}
                style={{ marginTop: '10px', width: '300px' }}
            />
        </div>
    )
}

export default TodoListUI

 

3.  Redux 发送异步请求 (使用redux-thunk)

  1. 使用 axios
  2. 使用 redux-thunk 将异步函数写在redux/动作文件里面, 不用redux-thunk的话可以将ajax 回调放在组件的生命周期函数里面

    但是,随着组件的内容增多, 组件可能相对的比较复杂, 所以建议还是使用中间件

生命周期函数直接提交函数

 componentDidMount(){
       const action = getTodoList();
       store.dispatch(action); // 当调用这个函数时, 异步函数会自动执行
    }

redux/action文件函数

export const getTodoList = () => {
   return (dispatch) => {
    axios.get('/list.json').then((res)=>{
        const data = res.data;
        const action = initListAction(data);
        dispatch(action);
    })
   }
};

store文件

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

const composeEnhancers =
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
      // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
    }) : compose;

const enhancer = composeEnhancers(
    applyMiddleware(thunk),
    // other store enhancers if any
);

const store = createStore(reducer,enhancer); 

export default store;

ps : 如果不适用 redux-thunk, 直接在生命周期函数中使用(但是不建议)

 componentDidMount(){
        axios.get('/list.json').then((res)=>{
        const data = res.data;
        const action = initListAction(data);
        dispatch(action);
    })
    }

 

4.  Redux 中间件

一般情况 : 在action通过 dispatch这个方法, 把对象发送给store

使用中间件: 中间件简单来说就是, 对store的dispatch方法进行升级, 允许传过来一个函数,而不是只能是对象. 在传过来的时候, 对传过来的action进行判断, 如果是函数,则先执行函数,再进行下一步的操作, 就好像这样,传递过来的函数立即执行, 这个函数默认参数是dispatch , 然后通过 dispatch 提交下一个action动作

使用的是redux-thunk中间件

export const getTodoList = () => {
   return (dispatch) => {
    axios.get('/list.json').then((res)=>{
        const data = res.data;
        const action = initListAction(data);
        dispatch(action);
    })
   }
};

ps : 只有redux才有中间件, 而不是react

5.  Redux-saga 的基本使用

1.  store/ index 下配置 (github上面有详细的配置)

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

const sagaMiddleware = createSagaMiddleware();
const composeEnhancers =
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(
    applyMiddleware(sagaMiddleware)
);

const store = createStore(reducer,enhancer); 
sagaMiddleware.run(mySaga);
export default store;

2.actionCreators.js 创建行为类型

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

3.  执行步骤, 组件周期函数派发action

 componentDidMount(){
        const action = getInitList();
        store.dispatch(action)
}

4.sagas.js 接收action判断行为类型 (使用方法详见github)  

   saga就是组件派发action后, 拦截下来, 优先处理,该类型的函数,

   但是与thunk不同的是, saga内置了一些方法可以处理异步函数

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

function* getInitList() {
    try{ // 成功的时候
        const res = yield axios.get('/list.json');
        const action = initListAction(res.data);
        yield put(action)
    }catch(e){
        console.log('list.json 网络请求失败')
    }  
}


// generator 函数
function* mySaga() {
    yield takeEvery(GET_INIT_LIST, getInitList); // 判断action类型,处理
}

export default mySaga;

5.saga 内置 put 方法继续提交action给reducer执行后面的步骤, 后面的就是redux常规的步骤

 

6.  React-Redux

1.  文件格式

2. index.js 入口文件

import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
import {Provider} from 'react-redux';
import store from './store';

// 这个标签里面的所有组件都可以使用store里面的数据
// Provider 这组件可以把store提供给它含的所有组件
const App=(
    <Provider store={store}> 
        <TodoList/>
    </Provider>
)

// JSX 语法
ReactDOM.render(App, document.getElementById('root'));

3.  组件

import React from 'react';
// import store from './store';
import { connect } from 'react-redux';

const TodoList =(props) => { // 无状态组件, 性能更佳
    
        const {inputValue,list,changeInputValue,putChange,delClick} = props
        return (                                                                                               
            
            <div>
                <div>
                    <input value={inputValue} onChange={changeInputValue} />
                    <button onClick={putChange}>提交</button>
                </div>
                <ul>
                    {list.map((item, index) => {
                       return <li key={index} onClick={delClick.bind(this, index)}>{item}</li>
                    })}
                    
                </ul>
            </div>
        )
    
}

// mapStateToProps 箭头函数里面的state是和store里面的state对应的
const mapStateToProps = (state) => {
    return {
        inputValue: state.inputValue,
        list:state.list
    }
}

// mapDispatchToProps 箭头函数里面的state是和store里面的state对应的
// store.dispatch, props
const mapDispatchToProps = (dispatch) => {
    return {
        changeInputValue(e) {
            const action = {
                type: 'change_input_value',
                value: e.target.value
            }
            dispatch(action);
        },
        putChange() {
            const action = {
                type: 'put_change'
            }
            dispatch(action)
        },
        delClick(index){
            const action = {
                type: 'del_click',
                index: index
            }
            dispatch(action)
        }
    }
}


// connect(null, null) (TodoList)
// 这个语法的意思是, 和store链接
// 第一个参数是state映射
// 第二个参数是action映射
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);

4. store/index.js

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

const store = createStore(reducer);

export default store;

5.  store/reducer.js

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

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==='put_change'){
        const newState = JSON.parse(JSON.stringify(state));
        newState.list.push(newState.inputValue);
        newState.inputValue = '';
        return newState;
    }
    if(action.type ==='del_click'){
        const newState = JSON.parse(JSON.stringify(state));
        newState.list.splice(action.index,1);
        return newState;
    }
    return state;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懂懂kkw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值