Redux,执行基本的可重用操作,以减少样板代码

时间:2018-08-31 16:13:24

标签: reactjs redux

最近开始使用React + Redux,因此,我可能会有错误的感觉,但是在我看来,在某些情况下,操作可以在整个应用程序中重用。

在我们的应用商店中,我们通常设置以下数据类型:

  • 字符串
  • 布尔值
  • 数组
  • 对象
  • 号码

我决定创建动作助手,该助手将与常量一起工作。下面是实现。请注意,它需要使用redux-thunk中间件。

//baseActions.js

function baseType(dispatch, payloadType, type, getState) {
    return async (initialPayload, transformer) => {
        var realPayloadType;
        switch (payloadType) {
            case 'array' :
                realPayloadType = Array.isArray(initialPayload) ? 'array' : null
                break
            default:
                realPayloadType = typeof initialPayload
        }

        if (realPayloadType !== payloadType && initialPayload !== null)
            throw new Error(`Payload should be ${payloadType}, but ${realPayloadType} provided`)

        const payload = transformer ? await transformer({payload: initialPayload, dispatch, getState}) : initialPayload

        return dispatch({
            type,
            payload
        })
    }
}

export function setNumber(actionType) {
    return (dispatch, getState) => {
        return baseType(dispatch, 'number', actionType, getState)
    }
}

export function setBoolean(actionType) {
    return (dispatch, getState) => {
        return baseType(dispatch, 'boolean', actionType, getState)
    }
}

export function setString(actionType) {
    return (dispatch, getState) => {
        return baseType(dispatch, 'string', actionType, getState)
    }
}

export function setArray(actionType) {
    return (dispatch, getState) => {
        return baseType(dispatch, 'array', actionType, getState)
    }

}

export function setObject(actionType) {
    return (dispatch, getState) => {
        return baseType(dispatch, 'object', actionType, getState)
    }
}

值得注意的是,除了有效负载外,方法还可以使用 transformer 函数,该函数可用于使我们的动作异步。 稍后我将在一个组件中显示一个示例。

现在我们可以将该文件导入到容器中

import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import User from '../components/User'
import {SET_USER_NAME} from '../constants/userConstants'
import * as actions from '../shared/actions/baseActions'

//App container

class App extends Component {
    render() {
        const { user } = this.props;
        const { setString } = this.props.actions

        return <User setName={setString(SET_USER_NAME)} name={user.first_name} avatar={user.avatar} />

    }
}

function mapStateToProps (state) {
    return {
        user: state.user
    }
}

function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators(actions, dispatch)
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

我要在容器中导入常量,而不是像通常那样进行操作。基本动作创建者不需要知道动作类型,因此您可以传递所需的动作类型。

import {SET_USER_NAME} from '../constants/userConstants'
import * as actions from '../shared/actions/baseActions'

然后我们可以将动作传递给属性中的组件

setName={setString(SET_USER_NAME)}

下面是User组件,带有异步操作示例。

import React, {Component } from 'react'
import PropTypes from 'prop-types'

export default class User extends Component {
    setAfterTimeout (params = {}) {
        //This method is for demonstration. Better if it is imported from external location
        const {payload, dispatch, getState} = params
        const state = getState() //Retrieve current state if needed
        return new Promise((res) => {
            //Call another dispatch if needed
            dispatch({
                type: 'SET_USER_NAME',
                payload: 'test'
            })

            //Call async method before dispatch
            setTimeout(() => {
                res(`${payload || ''} Doe`)
            }, 2000)
        })
    }
    render() {
        const { name, avatar, setName} = this.props
        return <div>
            <p>Hi, {name}!</p>
            <img onClick={() =>setName('John', this.setAfterTimeout)} src={avatar} alt=""/>
            {/*If you don't need initial payload, set it to null. e.g.  {() =>setName(null, this.setAfterTimeout)}*/}
        </div>
    }
}

User.propTypes = {
    name: PropTypes.string.isRequired,
    avatar: PropTypes.string.isRequired
}

setAfterTimeout 是一种转换器方法,允许在进行分发之前操纵异步数据。

我的主要问题:使用此模式有哪些潜在陷阱? 我认为最大的好处是不必为基本商店配件创建操作,例如放置在商店中的UI。它还允许在分派之前使用异步回调来转换有效负载。

0 个答案:

没有答案