From d61c502aac4386b88758773295ea11fa20e56ec7 Mon Sep 17 00:00:00 2001 From: lancely Date: Wed, 17 Jan 2024 11:04:24 +0800 Subject: [PATCH 1/6] fix(Menu): fix menu async load items renderMore issues, close #4660 --- components/menu/__tests__/index-spec.js | 48 ++++++++++++++++++++++++- components/menu/view/menu.jsx | 12 +++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/components/menu/__tests__/index-spec.js b/components/menu/__tests__/index-spec.js index ade542f451..43e8f48b73 100644 --- a/components/menu/__tests__/index-spec.js +++ b/components/menu/__tests__/index-spec.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React,{useEffect, useState} from 'react'; import ReactDOM from 'react-dom'; import Enzyme, { mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; @@ -978,6 +978,52 @@ describe('Menu', () => { document.body.removeChild(div); }); + it('should show renderMore when hozInLine & async load more items ', () => { + const div = document.createElement('div'); + document.body.appendChild(div); + + const items = []; + for (let i = 0; i < 50; i++) { + items.push(i); + } + function App() { + const [categoryList, setCategoryList] = useState(items); + useEffect(() => { + setCategoryList(items); + }, []); + + return ( + + {categoryList.map((index, v) => ( + + Sub option 1 + Sub option 2 + + ))} + + ); + } + + ReactDOM.render( + , + div + ); + + const menu = document.querySelector('.next-menu.next-hoz'); + assert(menu.querySelectorAll('li.next-menu-more.rendermore-class')); + + ReactDOM.unmountComponentAtNode(div); + document.body.removeChild(div); + }); + + + it('should support hozInLine with header&footer in hoz', () => { const div = document.createElement('div'); document.body.appendChild(div); diff --git a/components/menu/view/menu.jsx b/components/menu/view/menu.jsx index fdac3a3987..051be864e4 100644 --- a/components/menu/view/menu.jsx +++ b/components/menu/view/menu.jsx @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import cx from 'classnames'; import { polyfill } from 'react-lifecycles-compat'; import SubMenu from './sub-menu'; +import isEqual from 'lodash.isequal'; import ConfigProvider from '../../config-provider'; import { func, obj, dom, events, KEYCODE } from '../../util'; import { getWidth, normalizeToArray, isSibling, isAncestor, isAvailablePos, getFirstAvaliablelChildKey } from './util'; @@ -57,7 +58,7 @@ const addIndicators = ({ children, lastVisibleIndex, prefix, renderMore }) => { } let overflowedItems = []; - if (index > lastVisibleIndex) { + if (index >= lastVisibleIndex) { child = React.cloneElement(child, { // 别折叠不显示的 item,不占用真实的用户传入的 key key: `more-${index}`, @@ -479,7 +480,6 @@ class Menu extends Component { componentDidMount() { this.menuNode = findDOMNode(this); - this.adjustChildrenWidth(); if (this.props.hozInLine) { @@ -491,6 +491,9 @@ class Menu extends Component { if (prevState.lastVisibleIndex !== this.state.lastVisibleIndex) { this.adjustChildrenWidth(); } + if (!isEqual(this.props.children, prevProps.children)) { + this.adjustChildrenWidth(); + } } componentWillUnmount() { @@ -498,12 +501,15 @@ class Menu extends Component { } adjustChildrenWidth() { + const { direction, prefix, header, footer, hozInLine } = this.props; if (direction !== 'hoz' || !hozInLine) { + return; } if (!this.menuNode && !this.menuContent) { + return; } @@ -511,11 +517,13 @@ class Menu extends Component { spaceWidth; if (header || footer) { + children = this.menuContent.children; spaceWidth = getWidth(this.menuNode) - getWidth(this.menuHeader) - getWidth(this.menuFooter); } else { children = this.menuNode.children; spaceWidth = getWidth(this.menuNode); + console.log(children) } if (children.length < 2) { From c22f143fda412d35e80b457981af8ded7463f384 Mon Sep 17 00:00:00 2001 From: lancely Date: Wed, 17 Jan 2024 15:30:52 +0800 Subject: [PATCH 2/6] chore(Menu): update test: menu async load items renderMore issues, close #4660 --- components/menu/__tests__/index-spec.js | 6 ++++-- components/menu/view/menu.jsx | 3 --- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/components/menu/__tests__/index-spec.js b/components/menu/__tests__/index-spec.js index 43e8f48b73..aa976b452e 100644 --- a/components/menu/__tests__/index-spec.js +++ b/components/menu/__tests__/index-spec.js @@ -1015,8 +1015,10 @@ describe('Menu', () => { div ); - const menu = document.querySelector('.next-menu.next-hoz'); - assert(menu.querySelectorAll('li.next-menu-more.rendermore-class')); + const menu = document.querySelector('.next-menu'); + assert(menu.querySelectorAll('li.next-menu-item').length === 52); + assert(menu.querySelectorAll('li.next-menu-item.next-menu-more').length === 2); + assert(menu.querySelectorAll('li.menuitem-overflowed').length > 1); ReactDOM.unmountComponentAtNode(div); document.body.removeChild(div); diff --git a/components/menu/view/menu.jsx b/components/menu/view/menu.jsx index 051be864e4..ab0a46eeaa 100644 --- a/components/menu/view/menu.jsx +++ b/components/menu/view/menu.jsx @@ -504,12 +504,10 @@ class Menu extends Component { const { direction, prefix, header, footer, hozInLine } = this.props; if (direction !== 'hoz' || !hozInLine) { - return; } if (!this.menuNode && !this.menuContent) { - return; } @@ -523,7 +521,6 @@ class Menu extends Component { } else { children = this.menuNode.children; spaceWidth = getWidth(this.menuNode); - console.log(children) } if (children.length < 2) { From 42a2a378525ffe9329957d09af0fc3e07ce9994f Mon Sep 17 00:00:00 2001 From: lancely Date: Mon, 22 Jan 2024 19:21:32 +0800 Subject: [PATCH 3/6] fix(Menu): update fix menu async load items renderMore issues, close #4660 --- components/menu/__tests__/index-spec.js | 24 ++++++++++++------------ components/menu/view/menu.jsx | 7 +++---- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/components/menu/__tests__/index-spec.js b/components/menu/__tests__/index-spec.js index aa976b452e..994c8f43ef 100644 --- a/components/menu/__tests__/index-spec.js +++ b/components/menu/__tests__/index-spec.js @@ -978,7 +978,7 @@ describe('Menu', () => { document.body.removeChild(div); }); - it('should show renderMore when hozInLine & async load more items ', () => { + it('should show renderMore when hozInLine & async load more items ', done => { const div = document.createElement('div'); document.body.appendChild(div); @@ -987,7 +987,7 @@ describe('Menu', () => { items.push(i); } function App() { - const [categoryList, setCategoryList] = useState(items); + const [categoryList, setCategoryList] = useState([]); useEffect(() => { setCategoryList(items); }, []); @@ -1014,17 +1014,17 @@ describe('Menu', () => { , div ); - - const menu = document.querySelector('.next-menu'); - assert(menu.querySelectorAll('li.next-menu-item').length === 52); - assert(menu.querySelectorAll('li.next-menu-item.next-menu-more').length === 2); - assert(menu.querySelectorAll('li.menuitem-overflowed').length > 1); - - ReactDOM.unmountComponentAtNode(div); - document.body.removeChild(div); + setTimeout(() => { + const menu = document.querySelector('.next-menu'); + assert(menu.querySelectorAll('li.next-menu-item').length === 52); + assert(menu.querySelectorAll('li.next-menu-item.next-menu-more').length === 2); + assert(menu.querySelectorAll('li.menuitem-overflowed').length > 1); + ReactDOM.unmountComponentAtNode(div); + document.body.removeChild(div); + done(); + }, 9000); }); - - + it('should support hozInLine with header&footer in hoz', () => { const div = document.createElement('div'); diff --git a/components/menu/view/menu.jsx b/components/menu/view/menu.jsx index ab0a46eeaa..a6138852fd 100644 --- a/components/menu/view/menu.jsx +++ b/components/menu/view/menu.jsx @@ -488,10 +488,9 @@ class Menu extends Component { } componentDidUpdate(prevProps, prevState) { - if (prevState.lastVisibleIndex !== this.state.lastVisibleIndex) { - this.adjustChildrenWidth(); - } - if (!isEqual(this.props.children, prevProps.children)) { + if ( prevState.lastVisibleIndex !== this.state.lastVisibleIndex + || ( React.Children.toArray(this.props.children).length !== React.Children.toArray(prevProps.children).length) + ) { this.adjustChildrenWidth(); } } From f5fae06ef33fe86d2043e1e1c064f09ff7c68e62 Mon Sep 17 00:00:00 2001 From: lancely Date: Tue, 23 Jan 2024 21:16:44 +0800 Subject: [PATCH 4/6] fix(Menu): update for fix menu async load items renderMore issues, close #4660 --- components/menu/__tests__/index-spec.js | 17 +++++++---------- components/menu/view/menu.jsx | 5 +---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/components/menu/__tests__/index-spec.js b/components/menu/__tests__/index-spec.js index 994c8f43ef..cf23864073 100644 --- a/components/menu/__tests__/index-spec.js +++ b/components/menu/__tests__/index-spec.js @@ -1009,20 +1009,17 @@ describe('Menu', () => { ); } - ReactDOM.render( , div ); - setTimeout(() => { - const menu = document.querySelector('.next-menu'); - assert(menu.querySelectorAll('li.next-menu-item').length === 52); - assert(menu.querySelectorAll('li.next-menu-item.next-menu-more').length === 2); - assert(menu.querySelectorAll('li.menuitem-overflowed').length > 1); - ReactDOM.unmountComponentAtNode(div); - document.body.removeChild(div); - done(); - }, 9000); + const menu = document.querySelector('.next-menu'); + assert(menu.querySelectorAll('li.next-menu-item').length === 52); + assert(menu.querySelectorAll('li.next-menu-item.next-menu-more').length === 2); + assert(menu.querySelectorAll('li.menuitem-overflowed').length > 1); + ReactDOM.unmountComponentAtNode(div); + document.body.removeChild(div); + done(); }); diff --git a/components/menu/view/menu.jsx b/components/menu/view/menu.jsx index a6138852fd..950560ba5a 100644 --- a/components/menu/view/menu.jsx +++ b/components/menu/view/menu.jsx @@ -4,7 +4,6 @@ import PropTypes from 'prop-types'; import cx from 'classnames'; import { polyfill } from 'react-lifecycles-compat'; import SubMenu from './sub-menu'; -import isEqual from 'lodash.isequal'; import ConfigProvider from '../../config-provider'; import { func, obj, dom, events, KEYCODE } from '../../util'; import { getWidth, normalizeToArray, isSibling, isAncestor, isAvailablePos, getFirstAvaliablelChildKey } from './util'; @@ -58,7 +57,7 @@ const addIndicators = ({ children, lastVisibleIndex, prefix, renderMore }) => { } let overflowedItems = []; - if (index >= lastVisibleIndex) { + if (index > lastVisibleIndex) { child = React.cloneElement(child, { // 别折叠不显示的 item,不占用真实的用户传入的 key key: `more-${index}`, @@ -500,7 +499,6 @@ class Menu extends Component { } adjustChildrenWidth() { - const { direction, prefix, header, footer, hozInLine } = this.props; if (direction !== 'hoz' || !hozInLine) { return; @@ -514,7 +512,6 @@ class Menu extends Component { spaceWidth; if (header || footer) { - children = this.menuContent.children; spaceWidth = getWidth(this.menuNode) - getWidth(this.menuHeader) - getWidth(this.menuFooter); } else { From bf4ab0c77c47e27ff605d35424623b1a4f6c21ee Mon Sep 17 00:00:00 2001 From: lancely Date: Thu, 25 Jan 2024 10:42:21 +0800 Subject: [PATCH 5/6] fix(Menu): format code for fix menu async load items renderMore issues, close #4660 --- components/menu/view/menu.jsx | 71 ++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/components/menu/view/menu.jsx b/components/menu/view/menu.jsx index 950560ba5a..dbba2bb815 100644 --- a/components/menu/view/menu.jsx +++ b/components/menu/view/menu.jsx @@ -6,7 +6,14 @@ import { polyfill } from 'react-lifecycles-compat'; import SubMenu from './sub-menu'; import ConfigProvider from '../../config-provider'; import { func, obj, dom, events, KEYCODE } from '../../util'; -import { getWidth, normalizeToArray, isSibling, isAncestor, isAvailablePos, getFirstAvaliablelChildKey } from './util'; +import { + getWidth, + normalizeToArray, + isSibling, + isAncestor, + isAvailablePos, + getFirstAvaliablelChildKey, +} from './util'; const { bindCtx } = func; const { pickOthers, isNil } = obj; @@ -83,7 +90,15 @@ const addIndicators = ({ children, lastVisibleIndex, prefix, renderMore }) => { return arr; }; -const getNewChildren = ({ children, root, mode, lastVisibleIndex, hozInLine, prefix, renderMore }) => { +const getNewChildren = ({ + children, + root, + mode, + lastVisibleIndex, + hozInLine, + prefix, + renderMore, +}) => { const k2n = {}; const p2n = {}; @@ -149,7 +164,11 @@ const getNewChildren = ({ children, root, mode, lastVisibleIndex, hozInLine, pre switch (child.type.menuChildType) { case 'submenu': - newChild = cloneElement(child, props, loop(child.props.children, pos, undefined, childLevel)); + newChild = cloneElement( + child, + props, + loop(child.props.children, pos, undefined, childLevel) + ); break; case 'group': newChild = cloneElement( @@ -420,7 +439,11 @@ class Menu extends Component { tabbableKey, openKeys: this.getInitOpenKeys(props, _k2n, _p2n), selectedKeys: normalizeToArray(selectedKeys || defaultSelectedKeys), - focusedKey: !isNil(this.props.focusedKey) ? focusedKey : focusable && autoFocus ? tabbableKey : null, + focusedKey: !isNil(this.props.focusedKey) + ? focusedKey + : focusable && autoFocus + ? tabbableKey + : null, }; bindCtx(this, [ @@ -441,7 +464,11 @@ class Menu extends Component { if ('openKeys' in nextProps) { state.openKeys = normalizeToArray(nextProps.openKeys); // 从展开状态变为收起状态,才需要清空openKeys - } else if ('mode' in nextProps && nextProps.mode === 'popup' && prevState.lastMode === 'inline') { + } else if ( + 'mode' in nextProps && + nextProps.mode === 'popup' && + prevState.lastMode === 'inline' + ) { state.openKeys = []; } @@ -487,8 +514,10 @@ class Menu extends Component { } componentDidUpdate(prevProps, prevState) { - if ( prevState.lastVisibleIndex !== this.state.lastVisibleIndex - || ( React.Children.toArray(this.props.children).length !== React.Children.toArray(prevProps.children).length) + if ( + prevState.lastVisibleIndex !== this.state.lastVisibleIndex || + React.Children.toArray(this.props.children).length !== + React.Children.toArray(prevProps.children).length ) { this.adjustChildrenWidth(); } @@ -513,7 +542,8 @@ class Menu extends Component { if (header || footer) { children = this.menuContent.children; - spaceWidth = getWidth(this.menuNode) - getWidth(this.menuHeader) - getWidth(this.menuFooter); + spaceWidth = + getWidth(this.menuNode) - getWidth(this.menuHeader) - getWidth(this.menuFooter); } else { children = this.menuNode.children; spaceWidth = getWidth(this.menuNode); @@ -557,7 +587,10 @@ class Menu extends Component { this.menuItemSizes.forEach((liWidth, i) => { currentSumWidth += liWidth; - if ((i >= totalLen - 1 && currentSumWidth <= spaceWidth) || currentSumWidth + moreWidth <= spaceWidth) { + if ( + (i >= totalLen - 1 && currentSumWidth <= spaceWidth) || + currentSumWidth + moreWidth <= spaceWidth + ) { lastVisibleIndex++; } }); @@ -615,7 +648,9 @@ class Menu extends Component { if (open && index === -1) { if (mode === 'inline') { if (openMode === 'single') { - newOpenKeys = openKeys.filter(k => _k2n[k] && !isSibling(_k2n[key].pos, _k2n[k].pos)); + newOpenKeys = openKeys.filter( + k => _k2n[k] && !isSibling(_k2n[key].pos, _k2n[k].pos) + ); newOpenKeys.push(key); } else { newOpenKeys = openKeys.concat(key); @@ -736,7 +771,9 @@ class Menu extends Component { this.props.onOpen([], { key: this.state.openKeys.sort( - (prevKey, nextKey) => _k2n[nextKey].pos.split('-').length - _k2n[prevKey].pos.split('-').length + (prevKey, nextKey) => + _k2n[nextKey].pos.split('-').length - + _k2n[prevKey].pos.split('-').length )[0], open: false, }); @@ -770,9 +807,15 @@ class Menu extends Component { handleItemKeyDown(key, type, item, e) { if ( - [KEYCODE.UP, KEYCODE.DOWN, KEYCODE.RIGHT, KEYCODE.LEFT, KEYCODE.ENTER, KEYCODE.ESC, KEYCODE.SPACE].indexOf( - e.keyCode - ) > -1 + [ + KEYCODE.UP, + KEYCODE.DOWN, + KEYCODE.RIGHT, + KEYCODE.LEFT, + KEYCODE.ENTER, + KEYCODE.ESC, + KEYCODE.SPACE, + ].indexOf(e.keyCode) > -1 ) { e.preventDefault(); e.stopPropagation(); From 8b1c3bbd80f7b8e8fe9e6a0197c12ef75fbeb0d2 Mon Sep 17 00:00:00 2001 From: lancely Date: Thu, 25 Jan 2024 11:19:04 +0800 Subject: [PATCH 6/6] fix(Menu): format codes for fix menu async load items renderMore issues, close #4660 --- components/menu/__tests__/index-spec.js | 101 +++++++++++------------- 1 file changed, 48 insertions(+), 53 deletions(-) diff --git a/components/menu/__tests__/index-spec.js b/components/menu/__tests__/index-spec.js index cf23864073..c9d79381c2 100644 --- a/components/menu/__tests__/index-spec.js +++ b/components/menu/__tests__/index-spec.js @@ -1,4 +1,4 @@ -import React,{useEffect, useState} from 'react'; +import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import Enzyme, { mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; @@ -105,10 +105,7 @@ describe('Menu', () => { ); - const innerHTML = wrapper - .find('.next-menu') - .at(0) - .instance().innerHTML; + const innerHTML = wrapper.find('.next-menu').at(0).instance().innerHTML; assert(innerHTML.match('test-group-string')); assert(innerHTML.match('test-submenu-string')); }); @@ -203,7 +200,11 @@ describe('Menu', () => { it('paddingleft should only be related to inline mode', () => { wrapper = mount( - + 1 @@ -224,14 +225,8 @@ describe('Menu', () => { ); - const item1Level = wrapper - .find('#sub2-item') - .at(0) - .props().inlineLevel; - const item2Level = wrapper - .find('#suba2-item') - .at(0) - .props().inlineLevel; + const item1Level = wrapper.find('#sub2-item').at(0).props().inlineLevel; + const item2Level = wrapper.find('#suba2-item').at(0).props().inlineLevel; assert(item1Level === 3); assert(item2Level === 2); @@ -506,7 +501,12 @@ describe('Menu', () => { }; wrapper = mount( - + 0 1 @@ -516,10 +516,7 @@ describe('Menu', () => { ); - wrapper - .find('.next-menu-sub-menu .next-menu-item') - .at(0) - .simulate('click'); + wrapper.find('.next-menu-sub-menu .next-menu-item').at(0).simulate('click'); assert(called); assert.deepEqual(selectedKeys, ['0', '2']); assert(item.props._key === '2'); @@ -578,10 +575,7 @@ describe('Menu', () => { ); - wrapper - .find('.next-menu-sub-menu .next-menu-item') - .at(0) - .simulate('click'); + wrapper.find('.next-menu-sub-menu .next-menu-item').at(0).simulate('click'); assertUnselected(wrapper.find('.next-menu-sub-menu .next-menu-item').at(0)); }); @@ -922,7 +916,9 @@ describe('Menu', () => { try { assert(menu.querySelectorAll('li.next-menu-more').length === 2); - const indicator = menu.querySelectorAll('li.next-menu-more')[0].querySelector('.next-menu-item-inner'); + const indicator = menu + .querySelectorAll('li.next-menu-more')[0] + .querySelector('.next-menu-item-inner'); indicator.click(); const overlay = document.querySelector('.next-overlay-wrapper'); @@ -984,35 +980,26 @@ describe('Menu', () => { const items = []; for (let i = 0; i < 50; i++) { - items.push(i); + items.push(i); } function App() { - const [categoryList, setCategoryList] = useState([]); - useEffect(() => { - setCategoryList(items); - }, []); - - return ( - - {categoryList.map((index, v) => ( - - Sub option 1 - Sub option 2 - - ))} - - ); + const [categoryList, setCategoryList] = useState([]); + useEffect(() => { + setCategoryList(items); + }, []); + + return ( + + {categoryList.map((index, v) => ( + + Sub option 1 + Sub option 2 + + ))} + + ); } - ReactDOM.render( - , - div - ); + ReactDOM.render(, div); const menu = document.querySelector('.next-menu'); assert(menu.querySelectorAll('li.next-menu-item').length === 52); assert(menu.querySelectorAll('li.next-menu-item.next-menu-more').length === 2); @@ -1021,14 +1008,20 @@ describe('Menu', () => { document.body.removeChild(div); done(); }); - it('should support hozInLine with header&footer in hoz', () => { const div = document.createElement('div'); document.body.appendChild(div); ReactDOM.render( - + 0 @@ -1051,7 +1044,9 @@ describe('Menu', () => { const menu = document.querySelector('.next-menu.next-hoz'); assert(menu.querySelectorAll('li.next-menu-more').length === 2); - const indicator = menu.querySelectorAll('li.next-menu-more')[0].querySelector('.next-menu-item-inner'); + const indicator = menu + .querySelectorAll('li.next-menu-more')[0] + .querySelector('.next-menu-item-inner'); indicator.click(); const overlay = document.querySelector('.next-overlay-wrapper');