React相关知识点:关于Redux

·  阅读 1836

为什么用Redux

一些小型项目,只使用 React 完全够用了,数据管理使用props、state即可,那什么时候需要引入Redux呢? 当渲染一个组件的数据是通过props从父组件中获取时,通常情况下是A –> B,但随着业务复杂度的增加,有可能是这样的:A –> B –> C –> D –> E,E需要的数据需要从A那里通过props传递过来,以及对应的E –> A逆向传递callback。组件BCD是不需要这些数据的,但是又必须经由它们来传递,这样不太友好,而且传递的props以及callback对BCD组件的复用也会造成影响。或者兄弟组件之间想要共享某些数据,也不是很方便传递、获取等。诸如此类的情况,就有必要引入Redux`了。

注:其实 A --> B --> C --> D --> E 这种情况,React不使用props层层传递也是能拿到数据的,使用Context即可。

Redux 的三大基本原则

redux的核心概念就是store、action、reducer

约法三章

State 是只读的 react文档中说惟一改变 state 的方法就是触发 action,奇怪的是 我们说State是只读的,但是为啥现在又说可以修改了呢,其实我们并不是直接修改state,action”是用来向 store 表示要修改 state 的载体。所以我们并没有直接设置state的方法,使用了dispatch(action) 发送 action 至 store 是唯一改变 state 的方式

store

  1. UI唯一数据来源;
  2. 维持应用的 state; 
  3. 提供 getState() 方法获取 state; 
  4. 提供 dispatch(action) 方法更新 state; 
  5. 通过 subscribe(listener) 注册监听器; 通过 subscribe(listener) 返回的函数注销监听器。


action

必须拥有type属性,用来描述发生什么,action通过reducer处理生成newState后才能够更改store信息。但是为了更好的语义编程,Redux通过语句store.dispatch(action)来更新store,reducer对action的处理在内部处理。

reducer

仅仅只是根据action.type处理一下需要更新的state

创建目录


创建Store模块 数据源

//store/index.js

/*引入createStore 是用来创建一个数据源对象保存我们的数据的*/

import { createStore, applyMiddleware, compose } from 'redux';
import { createLogger } from 'redux-logger';
//引用数据源
// store是引用的reducer
// action会触发reducer
import allreducers from './reducers/index';
//数据处理后会返回给数据源 才能取到最新的数据  在根组件index里获取


const logger = createLogger();
const store = createStore(
    allreducers,
    applyMiddleware(logger)
)
console.log(store)
function listerner () {
    store.getState();
}
store.subscribe(listerner);

export default store;复制代码


传入Store

Store保存了整个应用的单一状态树,所有容器组件都需要从store中读取,我们可以store作为属性传递给每个组件,子组件通过props获取,但是如果嵌套过深,写起来会很麻烦。还好,react-redux提供一个叫provider的组件,他可以让所有组件都可以访问到store(他的实现原理实际上是利用了react的context功能),而不必显示的一层层传递了。
import { Provider } from 'react-redux'
import store from './store';


ReactDOM.render(
   <Provider store={store}>
      <BrowserRouter>
         {routes }
      </BrowserRouter>
   </Provider>,
    document.getElementById('app')
);复制代码

创建Reducer 处理业务数据

//reducers/index.js

import * as Types from 'src/store/constants'
import { combineReducers } from 'redux';

const initState = {
    isLogin: "未登录",
    themecolor: "red",
    count: 0
}


const loginReducer = (state = initState.isLogin ,action) => {
    switch (action.type) {
        case Types.LOGIN_TYPE:
            return state = action.isLogin
        default:
            return state
    }
}

const themeReducer = (state = initState.themecolor ,action) => {
    switch (action.type) {
        case Types.THEME_TYPE:
            return state = action.themecolor
        default:
            return state
    }
}

const counterReducer = (state = initState.count, action) => {
    switch(action.type) {
        case Types.ADD_TYPE: return state + 1;
        default: return state;
    }
}

export default combineReducers({
    isLogin:loginReducer,
    themecolor:themeReducer,
    count:counterReducer
})复制代码

注意:combineReducers() 函数的作用是把多个 reducer 合并成一个最终的 reducer 函数。

常量统一保存

//constants/index.js

/*常量统一保存,便于管理*/
export const LOGIN_TYPE = "LOGIN_TYPE"
export const THEME_TYPE = "THEME_TYPE"
export const ADD_TYPE = "ADD_TYPE"复制代码

创建Action模块

actions/index.js

import * as Types from 'src/store/constants'
export const loginAction = function(isLogin) {
    return {
        type: Types.LOGIN_TYPE,
        isLogin
    }
}

export const themeAction = function(themecolor) {
    return {
        type: Types.THEME_TYPE,
        themecolor
    }
}

export const addAction = () => {
    return {
        type: Types.ADD_TYPE
    }
}复制代码

组件调用

import React, {PureComponent} from "react"
import store from 'src/store'
import { loginAction,themeAction,addAction } from 'src/store/actions'

const counterfn = () => {
    document.getElementById("counter").innerHTML = store.getState().count
}
store.subscribe(counterfn);
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        var state = store.getState();
        return (
            <div>
                <div id="counter"></div>
                <div>
                    <button onClick={() => store.dispatch(addAction())}>add </button>
                </div>
            </div>
        )
    }
}
export default NwdLogin复制代码



注意:在不使用react-redux的情况下 必须使用store.subscribe(listener), store更新后回调listener,回调函数里面可以调用store.getStore()来获取更新后得state哟~

结合 react-redux使用

react-redux,redux和react的桥梁工具。 react-redux将组建分成了两大类,UI组建component和容器组件container。 

UI组件:

  1. 只负责 UI 的呈现,
  2. 不带有任何业务逻辑 没有状态(即不使用this.state这个变量) 
  3. 所有数据都由参数(this.props)提供 不
  4. 使用任何 Redux 的 AP

容器组件:

  1. 负责管理数据和业务逻辑,不负责 UI 的呈现 
  2. 带有内部状态 
  3. 使用 Redux 的 API

1)通过connect方法将React组件和Redux连接起来,react-redux 中引入了 connect

import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        console.log(this.props)
        return (
            <div>
                    {this.props.isLogin}
                    <button onClick={() => this.props.loginAction("已登录")}>设置登录状态</button>
                    <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>设置themecolor状态{this.props.themecolor}</button>
            </div>
        )
    }
}
const mapStateToProps = (state,ownProps) => {
    return {
        isLogin: state.isLogin,
        themecolor: state.themecolor
    }
}

const mapDispatchToProps = ((dispatch,ownPorps) => {
    return {
        loginAction: (isLogin) => dispatch({
            type: "LOGIN_TYPE",
            isLogin: isLogin
        }),
        themeAction: (themecolor) => dispatch({
            type: "THEME_TYPE",
            themecolor: themecolor
        })
    }
})

export default connect(mapStateToProps,mapDispatchToProps)(NwdLogin)复制代码





1)connect()() 其实这儿是两次函数调用。首先。connect() 返回了一个函数,然后我们立刻调用了这个函数并给它传递进第二个括号内的参数。第二个参数一般是一个 React 组件这是一种常见的“函数式编程”的写法。

2)connect() 的第一个参数是个返回了一个对象的函数 mapStateToProps,这个对象的属性将会变成 React 组件中的“props”的属性,你可以看到他们的值来自 store 的 state。这里我把这第一个参数命名为“mapStateToProps”,如命名所示,是希望它来将全局 states 转化成本地 component 的 props。 mapStateToProps() 将会接收到一个携带着完整的 Redux store 的参数 store,然后抽出本地组件需要的 states 转换成 props。

3)

如果不写mapDispatchToProps,只能自己手动调用this.props.dispatch()

import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        console.log(this.props)
        return (
            <div>
                    {this.props.isLogin}
                    <button onClick={() => this.props.dispatch(loginAction("已登录"))}>设置登录状态</button>
                    <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.dispatch(themeAction("#fff"))}>设置themecolor状态{this.props.themecolor}</button>
            </div>
        )
    }
}
const mapStateToProps = (state,ownProps) => {
    return {
        isLogin: state.isLogin,
        themecolor: state.themecolor
    }
}

/*const mapDispatchToProps = ((dispatch,ownPorps) => {
    return {
        loginAction: (isLogin) => dispatch({
            type: "LOGIN_TYPE",
            isLogin: isLogin
        }),
        themeAction: (themecolor) => dispatch({
            type: "THEME_TYPE",
            themecolor: themecolor
        })
    }
})*/

export default connect(mapStateToProps)(NwdLogin)复制代码

react-redux中connect的装饰器用法@connect

import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'

@connect(
    state => {
        return {
            isLogin: state.isLogin,
            themecolor: state.themecolor
        }
    },
    {
        loginAction,
        themeAction,
        addAction
    }
)
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        console.log(this.props)
        return (
            <div>
                    {this.props.isLogin}
                    <button onClick={() => this.props.loginAction("已登录")}>设置登录状态</button>
                    <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>设置themecolor状态{this.props.themecolor}</button>
            </div>
        )
    }
}
export default NwdLogin
复制代码

redux的bindActionCreators

bindActionCreators是redux的一个API,作用是将单个或多个ActionCreator转化为dispatch(action)的函数集合形式。 开发者不用再手动dispatch(actionCreator(type)),而是可以直接调用方法。


import React, {PureComponent} from "react"
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'

@connect(
    state => {
        return {
            isLogin: state.isLogin,
            themecolor: state.themecolor
        }
    },
    dispatch => bindActionCreators({loginAction,themeAction,addAction},dispatch)
)
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        console.log(this.props)
        return (
            <div>
                    {this.props.isLogin}
                    <button onClick={() => this.props.loginAction("已登录")}>设置登录状态</button>
                    <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>设置themecolor状态{this.props.themecolor}</button>
            </div>
        )
    }
}
export default NwdLogin

复制代码


分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改