rc-treenode
src/Tree.tsxreact
getDerivedStateFromPropsgit
function needSync(name: string) {
// 1. props前面没值,而且 props里面有值(第一次)
// 2. 数据 直接比较 相同否 第一次是 fieldNames 有可能变化的状况 treeData 变化的状况
// children的提示
return (!prevProps && name in props) || (prevProps && prevProps[name] !== props[name]);
}
复制代码
转化为github
/** * Convert `treeData` into entity records. * 生成一个 key entries 的一个映射 */
export function convertDataToEntities( dataNodes: DataNode[], { initWrapper, processEntity, onProcessFinished, externalGetKey, childrenPropName, fieldNames, }: { initWrapper?: (wrapper: Wrapper) => Wrapper; processEntity?: (entity: DataEntity, wrapper: Wrapper) => void; onProcessFinished?: (wrapper: Wrapper) => void; externalGetKey?: ExternalGetKey; childrenPropName?: string; fieldNames?: FieldNames; } = {}, /** @deprecated Use `config.externalGetKey` instead */ legacyExternalGetKey?: ExternalGetKey, ) {
// Init config
const mergedExternalGetKey = externalGetKey || legacyExternalGetKey;
const posEntities = {};
const keyEntities = {};
let wrapper = {
posEntities,
keyEntities,
};
if (initWrapper) {
wrapper = initWrapper(wrapper) || wrapper;
}
traverseDataNodes(
dataNodes,
item => {
const { node, index, pos, key, parentPos, level } = item;
const entity: DataEntity = { node, index, key, pos, level };
const mergedKey = getKey(key, pos);
// Pos 的key Map 映射
posEntities[pos] = entity;
// key 的key Map 映射
keyEntities[mergedKey] = entity;
// Fill children
entity.parent = posEntities[parentPos];
if (entity.parent) {
entity.parent.children = entity.parent.children || [];
entity.parent.children.push(entity);
}
if (processEntity) {
processEntity(entity, wrapper);
}
},
{ externalGetKey: mergedExternalGetKey, childrenPropName, fieldNames },
);
if (onProcessFinished) {
onProcessFinished(wrapper);
}
return wrapper;
}
复制代码
其中各类key 的复写或者使用用户的key 的这些操做能够忽略 只关注逻辑处理部分api
主要看 这个方法 conductExpandParent 传入两个数据数组
/** * If user use `autoExpandParent` we should get the list of parent node * @param keyList * @param keyEntities */
export function conductExpandParent(keyList: Key[], keyEntities: Record<Key, DataEntity>): Key[] {
const expandedKeys = new Set<Key>();
function conductUp(key: Key) {
if (expandedKeys.has(key)) return;
const entity = keyEntities[key];
if (!entity) return;
expandedKeys.add(key);
const { parent, node } = entity;
if (node.disabled) return;
if (parent) {
conductUp(parent.key);
}
}
(keyList || []).forEach((key) => {
conductUp(key);
});
return [...expandedKeys];
}
复制代码
递归调用 dig 函数markdown
把数据从antd
转成app
两个参数,parent 若是有的话。做为pos 的前半部分,index 做为表示节点在数组中的位置函数
做为扁平化后的数据存储。每次遍历都会往 flattenList push 一个元素
const flattenNode: FlattenNode = {
...omit(treeNode, [fieldTitle, fieldKey, fieldChildren] as any),
title: treeNode[fieldTitle],// 节点显示的label
key: mergedKey, // getKey 结果
parent, // 父级节点
pos, // getPosition 结果
children: null,
data: treeNode, // 原始数据
// 标识是否为数组的起始位置
isStart: [...(parent ? parent.isStart : []), index === 0],
// 标识是否为当前数组的结尾
isEnd: [...(parent ? parent.isEnd : []), index === list.length - 1],
};
复制代码
这个值有两种状况,一种是 boolean的 true|false 一种是 数组形式,函数上面 new Set是为了去重 若是 expandedKeySet 有值,便继续往下递归 // 为何 expandedKeySet 没有值。不继续往下递归。稍等看下
其余的key处理相对相似。主要是基于前面处理树状结构数据和节点数据生成的 keymap 和 list等。如下就不作解析了,具体主要代码贴在这里
主要处理方法是 calcSelectedKeys
/** * Return selectedKeys according with multiple prop * @param selectedKeys * @param props * @returns [string] */
export function calcSelectedKeys(selectedKeys: Key[], props: TreeProps) {
if (!selectedKeys) return undefined;
const { multiple } = props;
if (multiple) {
return selectedKeys.slice();
}
if (selectedKeys.length) {
return [selectedKeys[0]];
}
return selectedKeys;
}
复制代码
/** * Parse `checkedKeys` to { checkedKeys, halfCheckedKeys } style */
export function parseCheckedKeys(keys: Key[] | { checked: Key[]; halfChecked: Key[] }) {
if (!keys) {
return null;
}
// Convert keys to object format
let keyProps;
if (Array.isArray(keys)) {
// [Legacy] Follow the api doc
keyProps = {
checkedKeys: keys,
halfCheckedKeys: undefined,
};
} else if (typeof keys === 'object') {
keyProps = {
checkedKeys: keys.checked || undefined,
halfCheckedKeys: keys.halfChecked || undefined,
};
} else {
warning(false, '`checkedKeys` is not an array or an object');
return null;
}
return keyProps;
}
复制代码
至此,rc-tree 的数据整理部分就分析到这里 主要要理解的事情是,如何把数据的处理的复杂度下降到最小。理解前面的节点处理 convertDataToEntities 函数对后面函数的做用就理解了大半.