从自己的项目经验中,总结了为什么要封装自己的hooks:
- 当数据影响的页面很多时,类似消息推送的业务,之前的做法是将数据存到initialState,然后在数据需要修改的页面对数据进行监听。
这样操作虽然可行,但是会很繁琐,每个页面都得监听数据,代码比较冗余,维护成本较高。
那我们能用什么方法呢,一开始,我想到的就是写一个公共组件,在组建引入该组件,然后把子组件的data和改变data的方法传过去。
//Socketpage.jsx
import React, { useEffect, useState } from "react";
import { useModel, useLocation } from "@umijs/max";
function Socketpage({ data, setData,mainkey }) {
const { initialState,setInitialState } = useModel('@@initialState');
const { pathname } = useLocation();
useEffect(() => {
if (mainkey.indexOf(pathname) != -1) {
let newData = JSON.parse(JSON.stringify(data));
let cursocketdata = [], rowKey = '', operationtype = '';
if (initialState.socketdata && Object.keys(initialState.socketdata).length > 0) {
Object.entries(initialState.socketdata).map(([curkey, curoute]) => {
if (curkey == mainkey) {
cursocketdata = curoute?.data;
rowKey = curoute?.rowKey;
operationtype = curoute?.type;
}
});
}
cursocketdata.map(item => {
if (operationtype === 'add') {
newData.unshift(item);
} else if (operationtype === 'update') {
newData = newData?.map(it => {
if (it[rowKey] === item[rowKey]) {
return {
...it,
...item
}
} else {
return it;
}
});
} else if (operationtype === 'delete') {
newData = newData?.filter(it => it[rowKey] != item[rowKey]);
}
});
setData(newData);
setInitialState(s => {
if (s.socketdata) {
delete s.socketdata[mainkey];
}
return {
...s
}
})
}
}, [initialState.socketdata, pathname]);
return <></>
}
export default Socketpage;
//在数据需要更新的页面,组件运用(随便写在哪一级,只要不是第一级的dom)
<Socketpage data={data} setData={setData} mainkey='/iot/devicelist/modela' />
但是你会发现Socketpage.jsx返回的其实相当于不用返回任何东西。此时就应该想到有没有更好的办法,那就是自己写一个ahooks,代码如下:
//useSocketBase.js
import React, { useEffect, useState } from "react";
import { useModel, useLocation } from "@umijs/max";
const useSocketBase = (data = [], setData, mainkey) => {
const { initialState,setInitialState } = useModel('@@initialState');
const { pathname } = useLocation();
useEffect(() => {
if(mainkey.indexOf(pathname) != -1) {
let newData = JSON.parse(JSON.stringify(data));
let cursocketdata = [], rowKey = '', operationtype='';
if (initialState.socketdata && Object.keys(initialState.socketdata).length > 0) {
Object.entries(initialState.socketdata).map(([curkey, curoute]) => {
if (curkey == mainkey) {
cursocketdata = curoute?.data;
rowKey = curoute?.rowKey;
operationtype = curoute?.type;
}
});
}
cursocketdata.map(item => {
if (operationtype === 'add') {
newData = newData.unshift(item);
} else if (operationtype === 'update') {
newData = newData?.map(it => {
if (it[rowKey] === item[rowKey]) {
return {
...it,
...item
}
} else {
return it;
}
});
} else if (operationtype === 'delete') {
newData = newData?.filter(it=>it[rowKey] != item[rowKey]);
}
});
setData(newData);
setInitialState(s=>{
if (s.socketdata) {
delete s.socketdata[mainkey];
}
return {
...s
}
})
}
}, [initialState.socketdata,pathname]);
};
export default useSocketBase;
//运用
const mainkey = '/iot/devicelist/modela';
const s = useSocketBase(data,setData,mainkey);
如果用过ahooks中useRequest的小伙伴都知道,这个hooks会暴露run,runAsync这些方法,所以之后我们可以根据业务,自定义hooks也可暴露出来一些方法,以便业务的调用