React-Redux 基础学习

基本概念

整体的三大概念

Action

顾名思义,动作,就是体现出你想要对 State 做什么。比如 LogoHover 就是表明 Logo 被 Hover 的动作,AddName 就是添加名字,

Action 中 type 是必须的,其他的比如 Name、Logo Hover 的自定义字段的时候,就看自己的实际需求如何了

比如我们这里的 LogoHover 的Action,就是一个最简单的 Action:

const LOGOHOVER = 'LOGO_HOVER';


const logoHoverAction = LogoHover(dispatch){
	dispatch({type: LOGOHOVER});
}

又比如说我们的 AddName Action,我们让他传递一个 名称,我们给添加到名称列表中,那么 Action 如下:

const ADDNAME = 'ADD_NAME';


const addNameAction = addName(dispatch,name){
	dispatch({type: ADDNAME,name: name});
}

从上面代码可以看出来 Action 是需要至少接收 dispatch 这个值,如果有自己额外的值,自己再增加到方法上传递过来就好了。

另外就是如果 我们可以把 ActionType 定义成一个统一导出,否则后期维护 ActionType 又是一个痛苦的事情,而且这个 type 是 字符串,很容易出错,但是很难发现问题在哪儿。

Reducer

Reducer 在 Redux 里面是一个对于不同 Action 的具体响应代码,比如说我 LogoHover 这个 Action 是要改变 isLogoHover 的值(Hover 为 true,否则为 false),那么Reducer 里面写法就是如下:

private static initState = {
        isLogoHover:false
    };
public headerReducer(oldState = HeaderReducers.initState, action: any){
	const state = Object.assign({},oldState);
	state.isLogoHover = !state.isLogoHover;
	return state;
}

注意代码中的 Object.assign()如同 React 中不建议直接修改 State 而是通过深克隆 以避免导致奇怪的错误一样,Redux 不建议对 state 直接修改。所以上述代码不能直接写成:

private static initState = {
        isLogoHover:false
    };
public headerReducer(oldState = HeaderReducers.initState, action: any){
	oldState.isLogoHover = !oldState.isLogoHover;
	return oldState;
}

如果有多个 Action,那么把代码中加入 Switch 就阔以了,但是需要注意 default 分支的返回,需要直接返回 oldState(即不做任何改变)

Store

Store 就像名字一样,是一个共同的地方,在 Redux 里面保存了我们的 State,并且可以发起 Action等(这里需要注意,Redux 要求一个应用有且只有一个 Store,如果有非常复杂的 State,是通过建立多个 Reducer,并且使用combineReducers()来组合这些Reducer)

为什么要求只有一个?因为 Store 的本质是一颗状态树,在 React 里面单一数据流向的原则使得 State 管理复杂,于是有了状态提升,而这里的 Store 就相当于是提升到最上层的 State(可能不是很恰当),所以一个是最好的,多了即使没有冲突,但是也会失去大部分使用 Redux 的意义。

Store 有如下职责:

如何创建 Store?

我们可以通过 createStore() 来进行Store 的创建,这个方法一般传递一个Reducer(或者通过上述所说的 combineReducers() 组合得到的一个 Reducer),还有的参数是可选的,这个参数当是服务端渲染的时候可以使用到,通过传递 window.STATE_FROM_SERVER来完成服务端渲染

如何控制应用?

我们创建了 Store,怎么样才能让他掌控我们的应用呢,React-Redux 中给我们提供了 Provider,我们只需要把应用包含在 Provider 中并且通过 sotre 把我们创建的 Store 传递进去即可,如下(例如 我们的根节点是 App):

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import './index.scss';
import { createStore } from 'redux';
import { rootReducer } from './Redux/Reducers';


const store = createStore(rootReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root') as HTMLElement
);

这样便让 Store 掌控了全局了。

组件内的转换:

State 转换成 Props

组件内,我们需要把 Redux 处理完成的 State 赋值到 props 上,

可以通过定义成 静态并且接收至少一个 State参数的方法来传递给 connect进行这个工作(官网是 mapStateToProps),比如我们这里想要把 State 中的 isLogoHover 赋值到组件的 props 中:

import { connect } from 'react-redux';
*****类的定义以及其他业务代码,类名称为 HearderComponment
public static importStateToProps(headerState: any){
        debugger;
        const props = {
            isLogoHover: headerState.HeaderReducer.isLogoHover
        };
        return props;
    }
***类结束
export default connect(HearderComponment.importStateToProps
)(HearderComponment)

注意:

  • 如果使用 react-redux 的时候提示找不到定义的话,需要安装 @types/react-redux 包
  • 根据自己的导出层级来看这个 State 的解析,并不全部都是 state 中的直接子级就是我们想要的,比如上述代码。

Action 转换成 Props

组件内我们也需要把 Action 转换成 props 方便组件调用,

可以通过定义成静态并且接收至少一个 dispatch参数的方法传递给 connect来进行这个工作(官网是 mapDispatchToProps),比如我们把这里的 LogoHover Action 转换到组件的 props 中:

import { connect } from 'react-redux';

*****类的定义以及其他业务代码,类名称为 HearderComponment
private handler(e){
	this.props.LogoHoverAction();
}
public static importActionToProps(dispatch: any){
        return {
            LogoHoverAction: ()=>{
                return HeaderAction.LogoHover(dispatch);
            },
        }
    }

***类结束
export default connect(HearderComponment.importActionToProps
)(HearderComponment)

注意:

  • 如果使用 react-redux 的时候提示找不到定义的话,需要安装 @types/react-redux 包

数据流向

图片来源:https://segmentfault.com/a/1190000011474522

019/01/16 > React-Redux 基础学习 > 2055834352-59daefda643b8.png

来个栗子

我们现在就来动动手,实现一个 Logo Hover 之后切换图片,使得我们的 Logo 看起来更cool

整体页面的搭建我就不说了,那个不是重点,我们效果现在如下:

2019/01/16 > React-Redux 基础学习 > image2019-1-17_16-36-55.png

想要达到 Hover 的时候就有如下效果:

2019/01/16 > React-Redux 基础学习 > image2019-1-17_16-37-53.png

我们的 目录结构如下:

2019/01/16 > React-Redux 基础学习 > image2019-1-17_16-38-59.png

package.json

{
  "name": "nex-orion-blog-react",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@types/react-redux": "^7.0.0",
    "antd": "^3.12.1",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "react-redux": "^6.0.0",
    "react-scripts-ts-antd": "2.17.0",
    "redux": "^4.0.1"
  },
  "scripts": {
    "start": "react-scripts-ts-antd start",
    "build": "react-scripts-ts-antd build",
    "test": "react-scripts-ts-antd test --env=jsdom",
    "eject": "react-scripts-ts-antd eject"
  },
  "devDependencies": {
    "@types/jest": "^23.3.12",
    "@types/node": "^10.12.18",
    "@types/react": "^16.7.18",
    "@types/react-dom": "^16.0.11",
    "typescript": "^3.2.2"
  }
}

就来动手吧,

添加 Provider

注意:这里的顺序不是固定的,步骤随意

我们往 index.tsx中添加 Provider

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import './index.scss';

ReactDOM.render(
  <Provider>
    <App />
  </Provider>,
  document.getElementById('root') as HTMLElement
);

添加 Reducer

我们在 HeaderReducers.ts里面添加如下代码:

class HeaderReducers{
    private static initState = {
        isLogoHover:false
    };

    public headerReducer(oldState = HeaderReducers.initState, action: any){

        switch (action.type) {
            case 'LOGO_HOVER':
                const state = Object.assign({},oldState);
                state.isLogoHover = !state.isLogoHover;
                return state;
            default:
                return oldState;
        }
    }
}

export const HeaderReducer = new HeaderReducers().headerReducer;

这里我们就把 ActionTypeLOGO_HOVER进行了处理,并且默认情况直接返回了 oldState

添加 Action

我们在 HeaderPageAction.ts里面添加如下代码:

class HeaderPageAction{

    public LogoHover(dispatch: any){
        dispatch({type: 'LOGO_HOVER'});
    }
    
}

export const HeaderAction = new HeaderPageAction();

这里我们定义了一个 Action,并且进行分发到指定的 Reducer 处理中

修改 Component

添加 importStateToProps(headerState: any)解析Stateprops

修改 Header.tsx:

public static importStateToProps(headerState: any){
        const props = {
            isLogoHover: headerState.HeaderReducer.isLogoHover
        };
        return props;
    }
添加 importActionToProps 转换 Action 到 props

修改 Header.tsx:

import { HeaderAction } from 'src/Redux/Actions';
***类的其他代码
public static importActionToProps(dispatch: any){
        return {
            LogoHover: ()=>{
                return HeaderAction.LogoHover(dispatch);
            },
        }
    }
***
通过 connect 来链接组件和 State、Action

修改 Header.tsx:

import { connect } from 'react-redux';

***其他代码
export default connect(
    HearderComponment.importStateToProps,
    HearderComponment.importActionToProps
)(HearderComponment);

这里通过 connect方法,把 importStateToPropsimportActionToProps以及 HeaderComponent链接在一起(即把 ActionStateComponent关联起来了)

创建传递 Store

修改 index.tsx,通过 redux 的 createStore方法创建store 并且通过 Provider传递:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import './index.scss';
import { createStore } from 'redux';
import { HeaderReducer } from './Redux/Reducers';


const store = createStore(HeaderReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root') as HTMLElement
);

运行,效果达到了

默认效果:

2019/01/16 > React-Redux 基础学习 > image2019-1-17_16-36-55.png

Hover 之后:

2019/01/16 > React-Redux 基础学习 > image2019-1-17_16-37-53.png

由于动态图不好搞,所以打印了 console:

2019/01/16 > React-Redux 基础学习 > image2019-1-17_17-11-22.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值