最近开始使用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。它还允许在分派之前使用异步回调来转换有效负载。