React 写中后台应用 最佳实践

一 不建议使用 useUncontrolled

组件封装,最好同时支持受控使用和非受控使用(预防未来抽离组件 或者用于循环场景), 一般组件库会使用useUncontrolled, 但是业务代码最好不要

jsx 复制代码
const [state, setState] = useControllableValue<string>(props, {  
const

此类 hook 返回的 setState 支持传入值, 好一些的会支持传入函数,

此类 hook,一般受控非受控的标志是, value === undefined, 但是 ahooks 不是这样,

但是, 官方 useState const [state,setState] = useState() 返回的 setState 还支持批量更新,也就是传入回调函数,多次调用 setState, 但是这个 hook 是永远无法支持的,至少至今没见过

正确的做法: useState + useEffect

jsx 复制代码
const [state,setState] = useState(props.value)
useEffect(()=>{
setState(props.value)
},[props.value])

<Child value>

当然, 如果你的应用足够复杂,可以再次封装,参考xyflow

jsx 复制代码
useStoreUpdater<Node[]>(nodes, setNodes);

当然也可以显式表达非受控,使用 defaultvalue, 参考

jsx 复制代码
useEffect(() => {
    const edgesWithDefaults = defaultEdges?.map((e) => ({ ...e, ...defaultEdgeOptions }));
    setDefaultNodesAndEdges(defaultNodes, edgesWithDefaults);

    return () => {
      reset();
    };
  }, []);

二 父组件的状态,不要拆散后传给子组件,且尽量不要有多对

  1. 不要拆散,是因为当数据很复杂时, 书写onValueChange函数时,容易出问题, 这算是一个好习惯吧
  2. 不要有多对,是因为某些需求下,需要传入回调来支持批量更新, 但是万一你使用了 useUncontrolled,那就得重构,而我们封装组件应该尽量满足各种使用情况
jsx 复制代码
const [state,setState] = useState()

<Child  readonly={state.reanonly}  value={state.value} onValueChange={state.value=x}/>

// Child.tsx
useRequest([readonly,value]) // 模拟读取
const onChange = (newVal)=>{ // 模拟修改
 onValueChange(newVal)
}

三 Form组件 最好借助框架使用 Form + useForm

jsx 复制代码
const [state,setState] = useState()
 
const fetch = (values)=> {
console.log(state) // state 是陈旧的,所以需要通过参数传入, 
}

<Form onSubmit={values=> {
 setState(values); // 一次更新太多变量,跟容易出 bug, 
 fetch(values);
 setPage(1) // 假如fetch 需要 page, 那么page 也要放到形参里, 这是会无限增加附加度的方式
} } />

最好使用 useForm, 下降复杂度

jsx 复制代码
const [form] = useForm()

const fetch = ()=> { // 不需要任何参数了
const values =  form.getValues() 
}

<Form form={form} onSubmit={values=> {
form.setFieldsValue({
...values,
page:1
})
fetch();

} } />

类似于 useStateRef, 另外使用 antd 的Form组件,是因为 onValuesChange是由用户操作才会触发, 而 mantine-form 没有这个 api

jsx 复制代码
const [form] = useForm() // mantine 没有 onValuesChange, 你只能模拟

// 这段代码跟下面的将造成死循环, 使用 JSON.stringify hack 处理, 在极端场景下也会有问题

useEffect(()=>{
form.setValues(form.values)
},[form.values])

useEffect(()=>{
onChange(form.values)
},[form.values])

<Form form={form} >

四 使用 ahooks 的 useRequest

由于页面不总是查询按钮触发的查询, 或者请求可能在子组件,拿不到 loading,所以无法给按钮正确的 loading 效果, 我们需要保证数据的正确,所以最好使用 ahooks 的 useRequest

五 使用 SWR 来请求下拉列表

在复用下拉列表的场景里, 比如table 里行内编辑, 多个页面共用选择器等, 可以显著增加响应速度 不过注意接口最好是get, 因为类似的 react-query 和 swr, onfetch 推崇 restfulapi, 对 get 支持最好,比如重新校验只支持get, 使用时注意, 黑盒很多,不要过度滥用

六 弹窗编辑

推荐使用 antd 的 Form 来处理,initialValues 里放数据缺失时的默认值,不要放新增按钮的数据, 因为这将被用到合并, finalValue = {...initialValues, ...row}, 比自己写要轻松一些, 另外setValues 总是增加值, 不支持reset, 所以你的 Modal 最好是 {show? <Modal/>: null} 来销毁

七 尽量写完整的TS

需求变更时, 需要重构代码,字段增减等, 有个 ts 的话,会告诉你哪个文件要修改, 效率和安全性能提升特别特别多,特别是二次封装的组件, 优先级强于业务代码

相关推荐
Amd7944 分钟前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子
生椰拿铁You13 分钟前
09 —— Webpack搭建开发环境
前端·webpack·node.js
狸克先生24 分钟前
如何用AI写小说(二):Gradio 超简单的网页前端交互
前端·人工智能·chatgpt·交互
baiduopenmap38 分钟前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
loooseFish1 小时前
小程序webview我爱死你了 小程序webview和H5通讯
前端
菜牙买菜1 小时前
让安卓也能玩出Element-Plus的表格效果
前端
请叫我欧皇i1 小时前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_1 小时前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
guokanglun1 小时前
空间数据存储格式GeoJSON
前端
zhang-zan2 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium