我是靠谱客的博主 超帅老师,最近开发中收集的这篇文章主要介绍React中的设计模式 - 受控属性Control Props前言一、background二、实现总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

  • 前言
  • 一、background
      • 1.1 需求
      • 1.2 example
  • 二、实现
      • 2.1 example
      • 2.2 useToggle实现
      • 2.3 设计新的dispatch
      • 2.4 调用user的onChange逻辑
      • 2.5 final version
  • 总结

前言

最近开始学习React,跟着Kent学,有很多干货,这里分享Rect中的一个设计模式Control Props,这个设计方法跟React中的Control Component

文章中完整的示例代码可以查看 这里


一、background

1.1 需求

有时候用户希望能够控制state的改变,比如在Inpt的组件中,用户希望控制input中的value以及value改变的action,onChange;对于DOM组件来说,React已经提供了受控组件

对于自定义组件,也可以设计出受控props,只要用户需要,props的控制权应该可以交给用户

1.2 example

比如,对于自定义的Toggle组件,用户可以控制on以及onChange;如果用户不愿意控制,那么就使用props的default on以及onChange

 <Toggle on={bothOn} onChange={handleToggleChange} />
<Toggle on={bothOn} onChange={handleToggleChange} />

二、实现

2.1 example

这里会借用之前的Toggle组件的例子,向外提供control props的功能

2.2 useToggle实现

useToggle主要是给组件调用的props的,比如用户新建Toggle组件,那么组件需要用的props统一从useToggle中获得

首先不妨先设计useToggle可以接受的参数,其中on以及inChange都是需要做成受控props的

function useToggle({
initialOn = false,
reducer = toggleReducer,
onChange,
on: controlledOn
} = {}) {

由于Toggle向外会提供两个方法,toggle以及reset,在user么有修改情况之下,使用dispatch方法就行了

const toggle = () => dispatch({type: actionTypes.toggle})
const reset = () => dispatch({type: actionTypes.reset, initialState})

但是如果需要提供受控props,那么如果user提供的话,就应该使用user提供的
这里不妨设想user控制props情景如下,user控制on,提供了onChange的方法

 <Toggle on={bothOn} onChange={handleToggleChange} />
function handleToggleChange(state, action) {
if (action.type === actionTypes.toggle && timesClicked > 4) {
return
}
setBothOn(state.on)
setTimesClicked(c => c + 1)
}

也就是说,对于useToggle的dispatch来说需要处理两种情况

  1. user没有控制props,使用dispatch
  2. user控制props,调用user控制的方法

2.3 设计新的dispatch

根据上面的要求,不妨设计新的dispatch

 function dispatchWithOnChange(action) {
if (!onIsControlled) {
dispatch(action)
}
onChange?.(reducer({...state, on}, action), action)
}
const toggle = () => dispatchWithOnChange({type: actionTypes.toggle})
const reset = () => dispatchWithOnChange({type: actionTypes.reset, initialState})

2.4 调用user的onChange逻辑

这里主要讲一下,调用user方法的逻辑

onChange?.(reducer({...state, on}, action), action)

从2.2的API可以知道,user调用的是

onChange = {()=>handleToggleChange(state, action)}

所以需要传新的state以及action,使用reduedr(state, action)可以返回新的state,由于on也是受控props,所以需要单独提取出来,如下

(reducer({...state, on}, action)

2.5 final version

全部的实现(Switch组件以及css)可以到前言中codesandbox链接中参考

import * as React from "react";
import { Switch } from "./switch";
const callAll = (...fns) => (...args) => fns.forEach((fn) => fn?.(...args));
const actionTypes = {
toggle: "toggle",
reset: "reset"
};
function toggleReducer(state, { type, initialState }) {
switch (type) {
case actionTypes.toggle: {
return { on: !state.on };
}
case actionTypes.reset: {
return initialState;
}
default: {
throw new Error(`Unsupported type: ${type}`);
}
}
}
function useToggle({
initialOn = false,
reducer = toggleReducer,
onChange,
on: controlledOn
} = {}) {
const { current: initialState } = React.useRef({ on: initialOn });
const [state, dispatch] = React.useReducer(reducer, initialState);
console.log("test on is controller ", controlledOn);
const onIsControlled = controlledOn != null;
const on = onIsControlled ? controlledOn : state.on;
function dispatchWithOnChange(action) {
if (!onIsControlled) dispatch(action);
onChange?.(reducer({ ...state, on }, action), action);
}
const toggle = () => dispatchWithOnChange({ type: actionTypes.toggle });
const reset = () =>
dispatchWithOnChange({ type: actionTypes.reset, initialState });
function getTogglerProps({ onClick, ...props } = {}) {
return {
"aria-pressed": on,
onClick: callAll(onClick, toggle),
...props
};
}
function getResetterProps({ onClick, ...props } = {}) {
return {
onClick: callAll(onClick, reset),
...props
};
}
return {
on,
reset,
toggle,
getTogglerProps,
getResetterProps
};
}
function Toggle({ on: controlledOn, onChange }) {
const { on, getTogglerProps } = useToggle({ on: controlledOn, onChange });
const props = getTogglerProps({ on });
return <Switch {...props} />;
}
function App() {
const [bothOn, setBothOn] = React.useState(false);
const [timesClicked, setTimesClicked] = React.useState(0);
function handleToggleChange(state, action) {
if (action.type === actionTypes.toggle && timesClicked > 4) {
return;
}
setBothOn(state.on);
setTimesClicked((c) => c + 1);
}
function handleResetClick() {
setBothOn(false);
setTimesClicked(0);
}
return (
<div>
<div>
<Toggle on={bothOn} onChange={handleToggleChange} />
<Toggle on={bothOn} onChange={handleToggleChange} />
</div>
{timesClicked > 4 ? (
<div data-testid="notice">
Whoa, you clicked too much!
<br />
</div>
) : (
<div data-testid="click-count">Click count: {timesClicked}</div>
)}
<button onClick={handleResetClick}>Reset</button>
<hr />
<div>
<div>Uncontrolled Toggle:</div>
<Toggle
onChange={(...args) =>
console.info("Uncontrolled Toggle onChange", ...args)
}
/>
</div>
</div>
);
}
export default App;
export { Toggle };

总结

受控props可以类比受控组件,目的就是为了让用户有更多的控制权,以方便用户更多自定义的方法,提高了组建的可复用性

最后

以上就是超帅老师为你收集整理的React中的设计模式 - 受控属性Control Props前言一、background二、实现总结的全部内容,希望文章能够帮你解决React中的设计模式 - 受控属性Control Props前言一、background二、实现总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部