總結一下react項目中redux的基本使用方法,順便將其與vuex稍做對比學習,前端路漫漫
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.menuName
vue
// 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}; } }
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 } }
import { createStore } from "redux"; import reducer from '../reducer'; import { composeWithDevTools } from 'redux-devtools-extension'; //chrome調試工具 export default () => createStore(reducer,composeWithDevTools())
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') );
每一個用到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)
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