第一种方法,不使用任何插件和库
import React, { useState, useEffect, SetStateAction, Dispatch } from 'react';
// 定义expandedKeys的类型
type ExpandedKeysType = Set<string>;
// 自定义Hook:useExpandedKeys
function useExpandedKeys(initialKeys: ExpandedKeysType): [ExpandedKeysType, (key: string) => void] {
const [expandedKeys, setExpandedKeys] = useState(initialKeys);
// 切换某个key的展开/收起状态
const toggleByKey: (key: string) => void = (key) => {
setExpandedKeys((prevKeys) => {
const newKeys = new Set(prevKeys);
if (newKeys.has(key)) {
newKeys.delete(key);
} else {
newKeys.add(key);
}
return newKeys;
});
};
// 使用useEffect来监听expandedKeys的变化
useEffect(() => {
// 这里可以执行依赖于expandedKeys的操作
console.log('Expanded keys have changed:', expandedKeys);
// 注意:这里的代码会在每次expandedKeys变化时执行
}, [expandedKeys]); // 当expandedKeys变化时,这个effect会重新运行
return [expandedKeys, toggleByKey];
}
// 定义Item的类型
type ItemType = {
id: string;
name: string;
};
// 使用自定义Hook的的组件
function MyComponent() {
// 使用自定义Hook,初始值为一个空的Set
const [expandedKeys, toggleByKey] = useExpandedKeys(new Set<string>());
// 假设有一个item列表,我们为每个item渲染一个按钮来切换其展开/收起状态
const items: ItemType[] = [
{ id: 'item1', name: 'Item 1' },
{ id: 'item2', name: 'Item 2' },
// ...其他items
];
return (
<div>
{items.map((item) => (
<div key={item.id}>
<button onClick={() => toggleByKey(item.id)}>
{expandedKeys.has(item.id) ? '收起' : '展开'}
</button>
{expandedKeys.has(item.id) && <div>这里是{item.name}的展开内容</div>}
</div>
))}
</div>
);
}
export default MyComponent;
第二种方法,和第一种大同小异,只不过写法高级一些,并使用了额外的库和插件
import {useMap,useSet} from '@huse/collection';
import constate from 'constate';
import {Key,useCallback,useState} from 'react';
export function useSetWithToggleAndAllChecked(){
//存和当前全选状态相反的项的key
// eg:已全展开时,存的是收起的项的key
const [set,methods]=useSet<string>();
const [allChecked,setAllChecked]=useState(false);
const toggleByKey =useCallback(()=>{
(key:string)=>{
if(set.has(key)){
methods.delete(key);
}else {
methods.add(key);
}
}
},
[set,methods]
);
const internalSetAllChecked=useCallback(()=>{
(shouldAllChecked:boolean)=>{
methods.clear();
setAllChecked(shouldAllChecked);
}
},
[set,methods,allChecked]
);
const checkIfExpandedByKey=useCallback(()=>{
(key:string)=>{
const has =set.has(key);
if(allChecked){
return !has;
}else{
return has;
}
}
},
[set,methods,allChecked]
);
return {
set,
methods:{toggleByKey,setAllChecked,internalSetAllChecked},
isAllChecked:allChecked,
checkoutExpandedByKey,
}
};
export const [
ExpandedRowProvider,
useAreAllRowsExpanded,
useToggleRowsExpanded,
useToggleRowExpandedByKey,
useCheckIfExpandedByKey,
]=constate(
useSetWithToggleAndAllChecked,
value=>value.isAllChecked,
value=>value.methods.setAllChecked,
value=>value.methods.toggleByKey,
value=>value.checkIfExpandedByKey,
)
ExpandedRowProvider相当于提供一个conText上下文
//使用时,顶层组件
<ExpandedRowProvider>
</ExpandedRowProvider>
//这个key就是后端返回的Table列表数据的每一项key值,或者是id
const isExpanded = useCheckIfExpandedByKey()(key)
const toggleByKey = useToggleRowExpandedByKey();
<a onClick={()=>toggleByKey(key)}>{isExpanded?'收起':'展开'}</a>
代码一下简洁了好多.