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 函數對後面函數的做用就理解了大半.