概述
react-redux 简单封装
安装
npm install --save redux
npm install --save react-redux
npm install --save-dev redux-devtools
依照官方实例 Todo List
处理 reducers
// 官方例子
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
]
case 'TOGGLE_TODO':
return state.map(todo =>
(todo.id === action.id)
? {...todo, completed: !todo.completed}
: todo
)
default:
return state
}
}
export default todos
// 处理完的 todos.ts
// store/reducers/todos.ts
// 使用对象进行匹配,可将 actions 直接去掉
export interface TodoItem {
id: number
text: string
completed: boolean
}
export type TodoStateProps = TodoItem[]
let nextTodoId = 0
const mutations: { [key: string]: (state: TodoStateProps, payload: unknown) => TodoStateProps } = {
'ADD_TODO': (state: TodoStateProps, payload: unknown): TodoStateProps => {
const action = payload as TodoItem
return [
...state,
{
id: nextTodoId++,
text: action.text,
completed: false
}
]
},
'TOGGLE_TODO': (state: TodoStateProps, payload: unknown): TodoStateProps => {
const action = payload as TodoItem
return state.map(todo =>
(todo.id === action.id)
? { ...todo, completed: !todo.completed }
: todo
)
}
}
const todos = (state: TodoStateProps = [], action: { type: string }): TodoStateProps => {
const { type, ...payload } = action
if (mutations[type]) {
return mutations[type](state, payload)
} else {
return state
}
}
export default todos
// 调用方式
import React from 'react'
import { connect, DispatchProp } from 'react-redux'
let AddTodo = ({ dispatch }: DispatchProp<any>) => {
let input: HTMLInputElement | null
return (
<div>
<form
onSubmit={e => {
e.preventDefault()
if (input) {
if (!input.value.trim()) {
return
}
const timer = setTimeout(() => {
if (input) {
clearTimeout(timer)
dispatch({ type: 'ADD_TODO', text: input.value }) // 直接传入一个 action 对象即可
input.value = ''
}
}, 1000)
}
}}
>
<input
ref={node => {
input = node
}}
/>
<button type="submit">
Add Todo
</button>
</form>
</div>
)
}
export default connect()(AddTodo)
处理 component
// utils/index.ts
// 组件处理函数
import { PropsWithChildren } from 'react'
import { connect, Matching } from 'react-redux'
import { AnyAction } from 'redux'
import { stateProps, actions } from '../store/reducers'
// 执行异步的 reducers
const handleDispatchAction = async (dispatch: any) => {
return (action: AnyAction) => {
const { type, ...payload } = action
if (actions[type]) {
await actions[type](dispatch, payload)
} else {
throw new Error(`${type} 没找到对应的 action`)
}
}
}
// 规定类型
export type dispatchActionType = (action: AnyAction) => void
type PropsType<T> = PropsWithChildren<Matching<{ storeState: stateProps; ownProps: T; } & { dispatch: any; dispatchAction: dispatchActionType; }, T>>
// 使用泛型来规定 props 参数
export const componentConnect = <T> (component: (props: PropsType<T>) => JSX.Element) => {
// 将 state, dispatch, dispatchAction 通过函数参数的方式注入到函数内
const mapStateToProps = (state: stateProps, ownProps: Omit<T, 'storeState' | 'dispatch' | 'dispatchAction'>) => {
return {
storeState: state,
ownProps
}
}
const mapDispatchToProps = async (dispatch: any) => {
return {
dispatch,
dispatchAction: await handleDispatchAction(dispatch)
}
}
const connectComponent = connect(
mapStateToProps,
mapDispatchToProps
)(component)
return connectComponent
}
以 Link.js 为例
// 官方
// 通过组件加容器的方式进行处理
// components/Link.js
import React from 'react'
import PropTypes from 'prop-types'
const Link = ({ active, children, onClick }) => {
if (active) {
return <span>{children}</span>
}
return (
<a
href=""
onClick={e => {
e.preventDefault()
onClick()
}}
>
{children}
</a>
)
}
Link.propTypes = {
active: PropTypes.bool.isRequired,
children: PropTypes.node.isRequired,
onClick: PropTypes.func.isRequired
}
export default Link
// 官方
// containers/FilterLink.js
import { connect } from 'react-redux'
import { setVisibilityFilter } from '../actions'
import Link from '../components/Link'
const mapStateToProps = (state, ownProps) => {
return {
active: ownProps.filter === state.visibilityFilter
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
onClick: () => {
dispatch(setVisibilityFilter(ownProps.filter))
}
}
}
const FilterLink = connect(
mapStateToProps,
mapDispatchToProps
)(Link)
export default FilterLink
经过处理后的
import { MouseEventHandler, ReactNode } from 'react'
import { componentConnect } from '../utils'
import { stateProps } from '../store/reducers'
interface LinkProps { children: ReactNode, filter: string, storeState: stateProps, dispatch: any }
const Link = ({ storeState, children, dispatch, ...ownProps }: LinkProps) => {
if (storeState?.visibilityFilter === ownProps.filter) {
return <span>{children}</span>
}
const handleClick: MouseEventHandler<HTMLButtonElement> = (e) => {
e.preventDefault()
dispatch({ type: 'SET_VISIBILITY_FILTER', filter: ownProps.filter })
}
return (
<>
<button onClick={handleClick}>
{children}
</button>
</>
)
}
export default componentConnect<LinkProps>(Link) // 通过泛型传入 props 参数, 可在组件直接使用
处理异步的 reducers
以 visibilityFilter.js 为例
export type visibilityFilterStateProps = string
const mutations: { [key: string]: (state: visibilityFilterStateProps, payload: unknown) => visibilityFilterStateProps } = {
'SET_VISIBILITY_FILTER': (state, payload) => {
const action = payload as { filter: string }
return action.filter
}
}
// 添加一个处理异步的 actions
export const actions = {
'SYNC_SET_VISIBILITY_FILTER': async (dispatch: any, payload: unknown) => {
const params = payload as Object
await new Promise<void>((resolve, reject) => {
const timer = setTimeout(() => {
clearTimeout(timer)
dispatch({ type: 'SET_VISIBILITY_FILTER', ...params })
resolve()
}, 1000)
})
}
}
const visibilityFilter = (state: visibilityFilterStateProps = 'SHOW_ALL', action: { type: string, payload: unknown }): visibilityFilterStateProps => {
const { type, ...payload } = action
if (mutations[type]) {
return mutations[type](state, payload)
} else {
return state
}
}
export default visibilityFilter
核心处理部分
// 在 store/reducers/index.ts 中
// 使用 webpack 的 require.context 载入各个 reducers
// ts 环境记得添加 webpack 类型 npm i @types/webpack-env @types/node -D
const modules = require.context('.', false, /^./(?!index)w+.ts$/)
// 组合,导出 reducers 的 actions
export const actions = modules.keys().reduce((pre: { [key: string]: (dispatch: any, ...params: any) => void }, key: string) => {
return Object.assign(pre, modules(key).action || {})
}, {})
// 在 utils/index.ts 中
// 导入 actions
import { stateProps, actions } from '../store/reducers'
// 执行异步的 reducers
const handleDispatchAction = async (dispatch: any) => {
return (action: AnyAction) => {
const { type, ...payload } = action
if (actions[type]) {
await actions[type](dispatch, payload)
} else {
throw new Error(`${type} 没找到对应的 action`)
}
}
}
const mapDispatchToProps = async (dispatch: any) => {
return {
dispatch,
dispatchAction: await handleDispatchAction(dispatch) // 将 dispatchAction 一起注入到函数内
}
}
使用
import { MouseEventHandler, ReactNode } from 'react'
import { componentConnect, dispatchActionType } from '../utils'
import { stateProps } from '../store/reducers'
interface LinkProps { children: ReactNode, filter: string, storeState: stateProps, dispatch: any, dispatchAction: dispatchActionType }
const Link = ({ storeState, children, dispatch, dispatchAction, ...ownProps }: LinkProps) => {
if (storeState?.visibilityFilter === ownProps.filter) {
return <span>{children}</span>
}
const handleClick: MouseEventHandler<HTMLButtonElement> = async (e) => {
e.preventDefault()
await dispatchAction({ type: 'SYNC_SET_VISIBILITY_FILTER', filter: ownProps.filter }) // 使用 dispatchAction 进行调用
// dispatch({ type: 'SET_VISIBILITY_FILTER', filter: ownProps.filter })
}
return (
<>
<button onClick={handleClick}>
{children}
</button>
</>
)
}
export default componentConnect<LinkProps>(Link)
最后
以上就是清新绿草为你收集整理的react-redux 简单封装react-redux 简单封装的全部内容,希望文章能够帮你解决react-redux 简单封装react-redux 简单封装所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复