nodeList.tsx 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import React, { PureComponent } from 'react';
  2. import { isEqual } from 'lodash';
  3. import TreeContext from './treeContext';
  4. import Collapse from './collapse';
  5. import { FlattenNode, NodeListProps, NodeListState, TransitionNodes } from './interface';
  6. const getTreeNodeKey = (treeNode: FlattenNode) => {
  7. const { data } = treeNode;
  8. const { key } = data;
  9. return key;
  10. };
  11. export default class NodeList extends PureComponent<NodeListProps, NodeListState> {
  12. static contextType = TreeContext;
  13. constructor(props: NodeListProps) {
  14. super(props);
  15. this.state = {
  16. transitionNodes: [],
  17. };
  18. }
  19. static getDerivedStateFromProps(props: NodeListProps, prevState: NodeListState) {
  20. const { flattenNodes = [], motionKeys, motionType, flattenList = [] } = props;
  21. const hasChanged = !isEqual(prevState.cachedMotionKeys, motionKeys) ||
  22. !isEqual(prevState.cachedData.map(i => i.key), flattenNodes.map(i => i.key));
  23. const motionArr = [...motionKeys];
  24. if (!hasChanged || !motionArr.length) {
  25. return null;
  26. }
  27. const transitionNodes: TransitionNodes<FlattenNode> = [];
  28. const transitionRange: FlattenNode[] = [];
  29. let rangeStart = 0;
  30. let newState = {};
  31. const lookUpTarget = motionType === 'hide' && flattenList ? flattenList : flattenNodes;
  32. lookUpTarget.forEach((treeNode, ind) => {
  33. const nodeKey = getTreeNodeKey(treeNode);
  34. if (motionKeys.has(nodeKey)) {
  35. transitionRange.push(treeNode);
  36. if (nodeKey === motionArr[0]) {
  37. rangeStart = ind;
  38. }
  39. } else {
  40. transitionNodes.push(treeNode);
  41. }
  42. });
  43. transitionNodes.splice(rangeStart, 0, transitionRange);
  44. newState = {
  45. transitionNodes,
  46. cachedData: flattenNodes,
  47. cachedMotionKeys: motionKeys,
  48. cachedMotionType: motionType
  49. };
  50. return newState;
  51. }
  52. onMotionEnd = () => {
  53. typeof this.props.onMotionEnd === 'function' && this.props.onMotionEnd();
  54. this.setState({ transitionNodes: [] });
  55. };
  56. render() {
  57. const { flattenNodes, motionType, searchTargetIsDeep, renderTreeNode } = this.props;
  58. const { transitionNodes } = this.state;
  59. const mapData = transitionNodes.length && !searchTargetIsDeep ? transitionNodes : flattenNodes;
  60. const options = mapData.map(treeNode => {
  61. const isMotionNode = Array.isArray(treeNode);
  62. if (isMotionNode && !(treeNode as FlattenNode[]).length) {
  63. return null;
  64. }
  65. if (isMotionNode && (treeNode as FlattenNode[]).length) {
  66. const nodeKey = getTreeNodeKey(treeNode[0]);
  67. return (
  68. <Collapse
  69. motionType={motionType === 'show' ? 'enter' : 'leave'}
  70. key={`motion-${nodeKey}`}
  71. onMotionEnd={this.onMotionEnd}
  72. motion={Boolean(motionType)}
  73. >
  74. {treeNode.map(node => renderTreeNode(node))}
  75. </Collapse>
  76. );
  77. }
  78. return renderTreeNode(treeNode as FlattenNode);
  79. });
  80. return options;
  81. }
  82. }