面试题答案
一键面试设计思路
- 数据结构:使用树形结构来表示多级折叠菜单。每个节点包含菜单标题、是否展开状态、子菜单数组等信息。例如:
const menuData = [
{
title: '菜单1',
isOpen: false,
children: [
{ title: '子菜单1-1', isOpen: false, children: [] },
{ title: '子菜单1-2', isOpen: false, children: [] }
]
},
{
title: '菜单2',
isOpen: false,
children: []
}
];
- 组件结构:创建一个顶级菜单组件,该组件接收菜单数据并渲染。对于每个菜单节点,递归渲染子菜单。使用
createSignal
来管理节点的展开/折叠状态。 - 动态数据加载:在菜单节点需要加载子菜单数据时,使用
fetch
或其他数据请求库来获取数据。可以通过在节点数据中添加一个标志位(如isLoading
)来表示数据是否正在加载。 - 用户交互反馈:当用户点击菜单节点时,更新节点的展开/折叠状态,并在数据加载时显示加载指示器。
数据流向
- 初始数据:菜单数据从外部传入顶级菜单组件。
- 状态更新:用户点击菜单节点时,通过
createSignal
更新节点的展开/折叠状态。当需要加载子菜单数据时,触发数据请求,更新isLoading
状态。 - 数据传递:菜单组件将数据向下传递给子菜单组件,子菜单组件根据接收到的数据进行渲染。
利用核心概念优化性能
- createSignal:通过
createSignal
管理每个菜单节点的展开/折叠状态,使得状态更新局部化。只有状态发生变化的节点及其子节点会重新渲染,而不是整个菜单组件。例如:
import { createSignal } from 'solid-js';
const MenuItem = ({ item }) => {
const [isOpen, setIsOpen] = createSignal(item.isOpen);
return (
<div>
<button onClick={() => setIsOpen(!isOpen())}>{item.title}</button>
{isOpen() && <SubMenu items={item.children} />}
</div>
);
};
- createEffect:在数据加载时,可以使用
createEffect
来处理副作用。例如,当节点的isOpen
状态变为true
且子菜单数据为空时,触发数据加载:
import { createSignal, createEffect } from 'solid-js';
const MenuItem = ({ item }) => {
const [isOpen, setIsOpen] = createSignal(item.isOpen);
const [subMenuData, setSubMenuData] = createSignal([]);
const [isLoading, setIsLoading] = createSignal(false);
createEffect(() => {
if (isOpen() && subMenuData().length === 0) {
setIsLoading(true);
// 模拟数据请求
setTimeout(() => {
const newData = [/* 新数据 */];
setSubMenuData(newData);
setIsLoading(false);
}, 1000);
}
});
return (
<div>
<button onClick={() => setIsOpen(!isOpen())}>{item.title}</button>
{isLoading() && <p>加载中...</p>}
{isOpen() && subMenuData().length > 0 && <SubMenu items={subMenuData()} />}
</div>
);
};
通过这种方式,createEffect
只会在 isOpen
状态和 subMenuData
长度发生变化时触发,避免了不必要的重复请求,提高了性能。
完整代码示例
import { createSignal, createEffect, JSX } from'solid-js';
// 模拟菜单数据
const menuData = [
{
title: '菜单1',
isOpen: false,
children: []
},
{
title: '菜单2',
isOpen: false,
children: []
}
];
const SubMenu = ({ items }: { items: any[] }) => {
return (
<ul>
{items.map((item, index) => (
<MenuItem key={index} item={item} />
))}
</ul>
);
};
const MenuItem = ({ item }: { item: any }) => {
const [isOpen, setIsOpen] = createSignal(item.isOpen);
const [subMenuData, setSubMenuData] = createSignal([]);
const [isLoading, setIsLoading] = createSignal(false);
createEffect(() => {
if (isOpen() && subMenuData().length === 0) {
setIsLoading(true);
// 模拟数据请求
setTimeout(() => {
const newData = [/* 新数据 */];
setSubMenuData(newData);
setIsLoading(false);
}, 1000);
}
});
return (
<div>
<button onClick={() => setIsOpen(!isOpen())}>{item.title}</button>
{isLoading() && <p>加载中...</p>}
{isOpen() && subMenuData().length > 0 && <SubMenu items={subMenuData()} />}
</div>
);
};
const Menu = () => {
return (
<div>
<SubMenu items={menuData} />
</div>
);
};
export default Menu;
以上代码展示了如何使用 Solid.js 的 createSignal
和 createEffect
来实现一个包含多级折叠菜单、动态数据加载和用户交互反馈的复杂前端组件,并通过合理使用这些概念优化性能。