nodeList.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import React, { PureComponent } from 'react';
  2. import { isEqual } from 'lodash';
  3. import TreeContext from './treeContext';
  4. import { FlattenNode, NodeListProps, NodeListState, TransitionNodes } from './interface';
  5. import Collapsible from '../collapsible';
  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. isOpen: false
  18. };
  19. }
  20. static getDerivedStateFromProps(props: NodeListProps, prevState: NodeListState) {
  21. const { flattenNodes = [], motionKeys, motionType, flattenList = [] } = props;
  22. const hasChanged = !isEqual(prevState.cachedMotionKeys, motionKeys) ||
  23. !isEqual(prevState.cachedData.map(i => i.key), flattenNodes.map(i => i.key));
  24. const motionArr = [...motionKeys];
  25. if (!hasChanged || !motionArr.length) {
  26. return null;
  27. }
  28. const transitionNodes: TransitionNodes<FlattenNode> = [];
  29. const transitionRange: FlattenNode[] = [];
  30. let rangeStart = 0;
  31. let newState = {};
  32. const lookUpTarget = motionType === 'hide' && flattenList ? flattenList : flattenNodes;
  33. lookUpTarget.forEach((treeNode, ind) => {
  34. const nodeKey = getTreeNodeKey(treeNode);
  35. if (motionKeys.has(nodeKey)) {
  36. transitionRange.push(treeNode);
  37. if (nodeKey === motionArr[0]) {
  38. rangeStart = ind;
  39. }
  40. } else {
  41. transitionNodes.push(treeNode);
  42. }
  43. });
  44. transitionNodes.splice(rangeStart, 0, transitionRange);
  45. const isOpen = motionType === 'hide';
  46. newState = {
  47. transitionNodes,
  48. cachedData: flattenNodes,
  49. cachedMotionKeys: motionKeys,
  50. cachedMotionType: motionType,
  51. isOpen
  52. };
  53. return newState;
  54. }
  55. onMotionEnd = () => {
  56. typeof this.props.onMotionEnd === 'function' && this.props.onMotionEnd();
  57. this.setState({ transitionNodes: [] });
  58. };
  59. collapsibleRefCb = () => {
  60. const { motionType } = this.props;
  61. !isEqual(this.state.isOpen, motionType === 'show') && setTimeout(()=>{
  62. this.setState({
  63. isOpen: motionType === 'show',
  64. });
  65. }, 0);
  66. }
  67. render() {
  68. const { flattenNodes, motionType, searchTargetIsDeep, renderTreeNode } = this.props;
  69. const { transitionNodes, isOpen } = this.state;
  70. const mapData = transitionNodes.length && !searchTargetIsDeep ? transitionNodes : flattenNodes;
  71. const options = mapData.map(treeNode => {
  72. const isMotionNode = Array.isArray(treeNode);
  73. if (isMotionNode && !(treeNode as FlattenNode[]).length) {
  74. return null;
  75. }
  76. if (isMotionNode && (treeNode as FlattenNode[]).length) {
  77. const nodeKey = getTreeNodeKey(treeNode[0]);
  78. return (
  79. <Collapsible
  80. duration={200}
  81. ref={this.collapsibleRefCb}
  82. isOpen={isOpen}
  83. motion={Boolean(motionType)}
  84. key={`motion-${nodeKey}`}
  85. onMotionEnd={this.onMotionEnd}
  86. >
  87. {treeNode.map(node => renderTreeNode(node))}
  88. </Collapsible>
  89. );
  90. }
  91. return renderTreeNode(treeNode as FlattenNode);
  92. });
  93. return options;
  94. }
  95. }