Redux在React中的使用小結

總結一下react項目中redux的基本使用方法,順便將其與vuex稍做對比學習,前端路漫漫

作一個麪包屑title跟隨菜單欄名稱變換的功能

1.定義目錄

image.png

2.定義reducer

redux中的reducer類比vuex的mutations,都是更改state,不一樣點在於redux須要將新的state返回,vuex不須要,多個reducer能夠分多個js文件,而後在index.js中經過combineReducers將reducer合併,相似vuex的Modules,實例代碼:前端

// reducer/index.js

import { combineReducers } from 'redux'
import menu from './menu'  // 引入單獨的reducer子模塊
export default combineReducers({
    menu,
    // 能夠繼續添加其餘的reducer模塊
})

注意,模塊化後,組件中獲取state的值的時候,須要從對應的模塊裏去取,例如:state.menu.menuNamevue

// reducer/menu.js

import { type } from '../action';

const initialState = {
    menuName: '首頁' // 初始化一個menuName的值
};
export default (state = initialState, action) => {
    switch (action.type) {
        case type.SWITCH_MENU:
            return {
                ...state, // 須要將以前的state解構出來一塊兒返回
                menuName: action.menuName // 更新新的數據返回
            };
            break;
        default:
            return {...state};
    }
}

3.定義action

redux的action,是定義須要調用那個reducer,主要是根據type字段,對應reducer的action.type,同時也能夠傳遞一些參數,跟vuex的action同樣,提交的是一個mutation(reducer),經過mutation(reducer)去改變state的值,實例代碼:react

// action/index.js

export const type = {  // 統一管理全部的事件類型,方便項目總體的維護
    SWITCH_MENU : 'SWITCH_MENU'
};

export function switchMenu(menuName) { //具體的某一個action方法,用於改變某一個state的值
    return {
        type: type.SWITCH_MENU,
        menuName
    }
}

4.定義store

import { createStore } from "redux";
import reducer from '../reducer';
import { composeWithDevTools } from 'redux-devtools-extension'; //chrome調試工具

export default () => createStore(reducer,composeWithDevTools())

5.配置項目入口文件

import { Provider } from "react-redux"; // redux提供的高階組件,高階組件相似vue中的mixin
import store from './redux/store';

ReactDOM.render(
    // 將store傳入Provider,目的是使項目全局都能拿到store,將其做用域提高到全局
    <Provider store={store()}>
        <Router />
    </Provider>,
    document.getElementById('root')
);

6.組件中獲取state的值

每一個用到redux的頁面或者組件都須要使用redux的Api導出組件vuex

import { connect } from 'react-redux'; // 能夠理解其表面意思,將其組件和redux鏈接起來

// 中間省略一萬字...

export default connect(mapStateToProps,null)(Header)

connect方法返回一個方法,返回的方法的參數裏傳入當前須要使用到redux的類組件或者說函數組件,connect方法第一個參數是mapStateToProps,這個回調方法用於獲取state的值,connect回調回來會給mapStateToProps方法把state傳過來;
第二個參數是mapDispatchToProps,用於dispath一個action,跟vuex的套路差很少,一樣,connect方法回調的時候會把dispath方法回調傳進來。
兩個參數非必傳,用到哪一個傳哪一個,沒用到能夠傳null;
還有一個重要的概念就是,這兩個回調必須有返回,可想而知,接收state的確定要返回一個state,提交action方法的確定要返回一個用於提交action,改變state的方法;返回值須要從this.props中獲取
實例代碼以下:chrome

import React, {Component} from 'react';
import { Row, Col } from "antd";
import './index.less';
import { dates } from '../../utils';
import { connect } from 'react-redux';

class Header extends Component {

    componentWillMount() {
        this.setState({
            userName: '小聰忙'
        })
        let timer = setInterval(() => {
            let sysTime = dates.formatDate(Date.now());
            this.setState({
                sysTime
            })
        },1000)
        this.setState({
            timer
        })
    }

    componentWillUnmount() {
        this.setState({
            timer: null
        })
    }

    // 當前title的值從this.props.menuName中獲取
    render() {
        return (
            <div className="header">
                <Row className="header-top">
                    <Col span="24">
                        <span>歡迎,{this.state.userName}</span>
                        <a href="#">退出</a>
                    </Col>
                </Row>
                <Row className="breadcrumb">
                    <Col span="4" className="breadcrumb-title">
                        {this.props.menuName}
                    </Col>
                    <Col span="20" className="weather">
                        <span className="date">{this.state.sysTime}</span>
                        <span className="weather-detail">晴轉多雲</span>
                    </Col>
                </Row>
            </div>
        );
    }
}

//定義一個用於接收state裏某個值的回調函數,必須有返回值,才能從props中獲取到這個值
const mapStateToProps = state => {
    return {
        // 特別注意,使用過vuex模塊化開發的就應該知道,獲取state的值的時候也須要從對應的模塊中去獲取
        menuName: state.menu.menuName
    }
};

export default connect(mapStateToProps,null)(Header)

7.改變state的值

import React, {Component} from 'react';
import './index.less';
import { Menu } from 'antd';
import menuConfig from '../../config/menuConfig';
import { NavLink } from "react-router-dom";
import { connect } from 'react-redux';
import { switchMenu } from '../../redux/action';

const { SubMenu } = Menu;

class NavLeft extends Component {
    componentWillMount() {
        const menuTreeNode = this.renderMenu(menuConfig);
        this.setState({
            menuTreeNode
        })
    }

    renderMenu = (menuConfig) => {
        return menuConfig.map((item,index) => {
            if (item.children && item.children.length) {
                return (
                    <SubMenu title={item.title} key={item.key} onClick={this.handleClick}>
                        {this.renderMenu(item.children)}
                    </SubMenu>
                )
            }
            return (
                <Menu.Item title={item.title} key={item.key}>
                    <NavLink to={item.key}>
                        {item.title}
                    </NavLink>
                </Menu.Item>
            )
        })
    }

    // this.props中獲取mapDispatchToProps回調返回的方法
    
    render() {
        const { handleClick } = this.props;
        return (
            <div>
                <div className="logo">
                    <img src="/assets/logo-ant.svg" alt=""/>
                    <h1>Imooc ms</h1>
                </div>
                <Menu theme="dark" onClick={handleClick.bind(this)}>
                    {this.state.menuTreeNode}
                </Menu>
            </div>
        );
    }
}

// 回調接收兩個參數,第一個是dispath方法,第二個是`ownProps`,它表明組件自己的props,若是寫了第二個參數`ownProps`,那麼當`prop`發生變化的時候,`mapStateToProps`也會被調用
const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        handleClick: ({item}) => dispatch(switchMenu(item.props.title))
    }
}

export default connect(null,mapDispatchToProps)(NavLeft);

最終效果圖:redux

2020-07-03 15-05-52.2020-07-03 15_06_10.gif

相關文章
相關標籤/搜索