antdCascader(或TreeSelec)仅根据最后一级value回显完整路径
Cascader(或TreeSelect树选择器 )往往会在项目中用在分类管理这一需求,可以很好的展示分类的层级结构,有时可能因为分类会存在改变层级(如由四级分类变成了二级分类)的情况,后端接口会要求在存储分类数据的时候,仅传递 最后一级 的信息。 例子
举个antd官网的例子: import { Cascader } from "antd"; const options = [ { value: "zhejiang", label: "Zhejiang", children: [ { value: "hangzhou", label: "Hangzhou", children: [ { value: "xihu", label: "West Lake", }, ], }, ], }, { value: "jiangsu", label: "Jiangsu", disabled: true, children: [ { value: "nanjing", label: "Nanjing", children: [ { value: "zhonghuamen", label: "Zhong Hua Men", }, ], }, ], }, ]; function onChange(value) { console.log(value); } ReactDOM.render(, mountNode);
在选中 Zhejiang / Hangzhou / Wes tLake 时,对应的value是 ["zhejiang", "hangzhou", "xihu"] ,后端可能只需要你传递xihu 即可,而非数组形式的网站路径信息。
这时前端在回显的时候会出现一个问题,无法根据 xihu 完整的回显之前的路径名Zhejiang / Hangzhou / Wes tLake了。如何收集完整的节点路径信息
我们可以借助官网在TreeSelect给的提示 onChange时如何获得父节点信息?
其思路就是将节点value作为对象 valueMap 的key,遍历节点的子节点children(如果有的话),通过parent该节点和其子节点链接起来。后续就可以用getPath 方法根据value 在valueMap 通过parent 一层一层找到对应的父节点信息了。const valueMap = {}; function loops(list, parent) { return (list || []).map(({ children, value, label }) => { const node = (valueMap[value] = { parent, data: { label, value } }); node.children = loops(children, node); return node; }); } loops(treeData); function getPath(value, prop) { const path = []; let current = valueMap[value]; while (current) { path.unshift(current.data[prop]); current = current.parent; } return path; }
简单改造下,同时 valueMap 同时收集下lable 信息,同时getPath 支持返回指定prop 的信息,让回显更加灵活。如何使用getPath完成数据方法一:我们可以直接通过ref暴露出去
useImperativeHandle(ref, () => ({ valueMap, getPath, }))
但是这样在部分使用起来不合适,比如列表展示时,并且这样也会存在因为列表数据渲染时`Cascader`的`valueMap`还未收集好,而`getPath`获取结果为空的情况。
我们可以试试方法二 方法二:支持自定义renderfunction CategorySelect(props, ref) { const [value, setValue] = useState([]); const [valueMap, setValueMap] = useState({}); // 根据value回显对应的label const fullLabelPath = useMemo(() => { if (!props.displayLabel) { return; } return getPath(props.value, props.displayLabel); }, [props.displayLabel, props.value, props.data, valueMap]); ... return { (props.fullLabelRender) ? props.fullLabelRender(fullLabelPath) : ( ) } }
我们将全路径的渲染能力开放通过`props.fullLabelRender`
使用可以这样使用 fullLabelRender={(fullLabelPath) => ({ fullLabelPath.join(" / ") })}
因为 fullLabelPath 是useMemo 的返回值,valueMap 是useState 的返回值,这样我们也不必担心列表数据渲染时Cascader的valueMap 还未收集好的情况了,待valueMap 收集完毕后,自会重新渲染的。
同样的思路也可以用在TreeSelect树选择器,我就不具体写了哦。