Redux状态管理与React-router

Redux状态管理

  • 概念:Redux是专注于状态管理的库
  • 组成:store,state,action,reducer
  • 安装:yarn add redux
  • 补充:不仅仅是React,在Vue和Angular中也可以使用Redux
1,基本介绍
  • store:数据源,用于存储状态(state)
  • state:React中的状态,是只读对象,不可直接修改
  • reducer:基本函数,用于对state的业务处理
  • action:普通对象,用于描述事件的行为,改变state
2,工作流
  • 用户的一个行为(比如鼠标点击)会触发Action
  • Action会分发(dispatch)给Reducer
  • 在Reducer中会对状态(stata)做相应的修改,并保存到数据源(STORE)中
  • 组件(Component)会监听数据源(STORE)中state的变化,从而改变页面的展示内容
image.png
3,调试工具安装(可选,建议安装)
  • 添加Chrome扩展程序Redux Devtools
  • 安装第三方库redux-devtools-extension:yarn add redux-devtools-extension
4,在React中使用Redux(以切换菜单为例)
  • 安装react-redux插件:yarn add react-redux
  • 创建Action模块
// 文件:src/redux/action/index.js

// Action类型
export const type = {
    SWITCH_MENU:'SWITCH_MENU'
}

// Action函数
// 参数:用户点击的某个菜单名称
// 返回值:对象,包括事件类型和用户点击的菜单名称的对象
export function switchMenu(menuName){
    return{
        type:type.SWITCH_MENU,  // 事件类型
        menuName                // 菜单名称
    }
}
  • 创建Reducer模块
// 文件:src/redux/reducer/index.js

// 引入action类型
import { type } from './../action';

// 初始化state
const initialState = {
    menuName:'首页',
}

// 业务处理函数
// 参数1:状态(state),参数2:动作(action)
// 返回值:对象,是一个包括所有最新state的对象
export default (state = initialState, action) => {
    switch (action.type) {
        // 切换菜单
        case type.SWITCH_MENU:
            return {
                ...state,                 // 通过对象解构的方式保留原来的所有state
                menuName:action.menuName  // 更新menuName
            }
        default:
            return {
                ...state
            };
    }
} 
  • 创建Store模块
    如果没有安装调试工具redux-devtools-extension,这样写。
// 文件:src/redux/store/index.js

// 引入reducer
import reducer from './../reducer';

// 引入createStore。这是Redux中的一个方法,用于创建一个数据源对象,保存数据
import { createStore } from 'redux';

// 导出数据源
export default () => createStore(reducer)

如果已经安装调试工具redux-devtools-extension,这样写。可以用Redux Devtools清楚地看到redux状态的变化(如果出错了,就用上一种写法,比较保险)

// 文件:src/redux/store/index.js

// 引入reducer
import reducer from './../reducer';

// 引入createStore。这是Redux中的一个方法,用于创建一个数据源对象,保存数据
import { createStore } from 'redux';

// 引入调试工具redux-devtools-extension
import { composeWithDevTools } from 'redux-devtools-extension';

// 导出数据源,可以方便地看到state变化
export default () => createStore(reducer,composeWithDevTools())
  • 添加Provider作为项目的根组件,用于数据的存储
// 文件:index.js

import { Provider } from 'react-redux';      // 引入Provider组件,用于提供数据源
import configureStore from './redux/store';  // 导入数据源创建方法
const store = configureStore();              // 创建数据源

// 用Provider组件包裹根组件Router,以提供数据源
// 这样Router里面的所有组件,都可以从数据源中获取数据
ReactDOM.render(
    <Provider store={store}>
        <Router />
    </Provider>,
    document.getElementById('root'));
  • 通过connect方法将React组件和Redux连接起来
    更新redux的状态
import { connect } from 'react-redux';              // 引入react-redux的connect方法
import { switchMenu } from './../../redux/action';  // 引入已经定义好的action

class Sidebar extends React.Component {
    // ...省略...
    currentTitleManage = () => {
        // ...省略...
        this.props.dispatch(switchMenu(currentTitle));  // 触发switchMenu动作
        // ...省略...
    }
    // ...省略...
}

// 通过connect方法连接Sidebar组件和redux
export default connect()(Sidebar);

取得redux的状态

import { connect } from 'react-redux';

class Header extends React.Component {
    // ...省略...
    {this.props.menuName}  // 取得菜单名称
    // ...省略...
}

// 获取数据源
const mapStateToProps = state => {
    return {
        menuName: state.menuName
    }
}

// 通过connect方法连接Header组件和redux
export default connect(mapStateToProps)(Header);

React-router

  • 安装:yarn add react-router-dom
    为什么要安装react-router-dom而不是react-router?
    因为在React Router 4.0中,react-router-dom是专门用于浏览器端的路由控制器,其中已经包含了基础路由(react-router),所有我们只需要安装react-router-dom就可以了。
1,react-router和react-router-dom理解
  • react-router:提供了一些router的核心api,包括Router,Route,Switch等
  • react-router-dom:提供了BrowserRouter,HashRouter,Route,Link,NavLink
2,react-router-dom核心用法
    // path:路径,component:路径对应的组件
    <Route path="/login" component={Login}/>

    // render:添加子路由
    // exact:精准匹配
    <Route path='/' render={()=>
        this.props.logout ? 
        (
            <Redirect to={`/login`}/>
        ) :
        (
            <Admin>
                <Switch>
                    <Route path="/home" component={Home}/>
                    <Route exact path='/contracts/list' component={ContractList}/>
                    ...
  • NavLink,Link
// NavLink:主要用于菜单导航

import { NavLink } from 'react-router-dom';

    // 第一种写法:to地址
    <NavLink to='/home' replace>
        <span>首页</span>
    </NavLink>

    // 第二种写法:to对象,对象里包含一个pathname属性
    <NavLink to={pathname:'/home'} replace>
        <span>首页</span>
    </NavLink>

    // 第三种写法:to对象,对象里包含比较多的属性
    <NavLink to={pathname:'/home',search:'',hash:'',key:'123',state:{}} replace>
        <span>首页</span>
    </NavLink>
// Link:主要用于链接
// 用法与NavLink一致
  • Switch
// 单个路由匹配:如果匹配到一个路由,就结束匹配
    <Switch>
        <Route path="/home" component={Home}/>
        <Route path='/contracts/list/add' component={ContractListDetail}/>
        <Route path='/contracts/list/edit/:id' component={ContractListDetail}/>
    </Switch>
  • Redirect
// 路由重定向

<Redirect to='/login'/>  // 重定向到login
  • 嵌套子路由
// "/home"是"/"下的子路由,需要用render的形式

<Route path='/' render={()=>
    <Admin>
        <Switch>
            <Route path="/home" component={Home}/>
        </Switch>
    </Admin>
}/>
// Admin组件

export default class Admin extends React.Component{
    render() {
        return (
            <Layout style={{ minHeight: '100vh' }}>
                <Sidebar/>
                <Layout>
                    <Header/>
                    <Content style={{ padding: '10px 10px 0'}}>
                        {this.props.children}  // 这里就是各个子路由对应的组件
                    </Content>
                    <Footer/>
                </Layout>
            </Layout>
        );
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354