React列表key警告修复 函数组件Materialize汉堡菜单实现
修复方案
一、"Each child in a list should have a unique 'key' prop" 警告修复
问题原因
两处遍历categories数组渲染列表的代码存在两个错误:
- map回调的单个元素参数是
category,但代码里错误引用了整个数组对象categories的属性,数组本身不存在id/route/name字段,导致所有渲染项的key值都是undefined,不满足唯一key要求 - key属性需要绑定在遍历返回的最外层根元素上,当前代码错误把key绑在了内部的
NavLink组件上,外层<li>作为列表直接子元素没有拿到key
修复代码
把桌面端导航、移动端侧边栏两处的map遍历逻辑统一替换为以下写法:
{ categories.map((category) => ( <li key={category.id}> <NavLink to={category.route}>{category.name}</NavLink> </li> )) }
二、函数组件下Materialize汉堡侧边栏功能实现
实现逻辑
类组件中一般在componentDidMount生命周期初始化Materialize的JS交互实例,函数组件中使用useEffect钩子实现等价的挂载后初始化逻辑即可,步骤如下:
- 补充引入React的
useEffect钩子,以及Materialize的JS交互模块(之前只引入了CSS样式,缺少交互逻辑代码) - 在组件挂载完成后调用Materialize的Sidenav初始化方法,绑定侧边栏触发逻辑
- 组件卸载时销毁侧边栏实例,避免内存泄漏
修复后完整组件代码
import React, { useEffect } from 'react'; import M from 'materialize-css'; import 'materialize-css/dist/css/materialize.css'; import logo from '../MKY.png'; import Cart from './CartWidget'; import { Link, NavLink} from 'react-router-dom'; const Navbar = () => { const categories = [ { name: "electronics", id: 0, route: "/category/electronics" }, { name: "jewelery", id: 1, route: "/category/jewelery" }, { name: "men's clothing", id: 2, route: "/category/men's clothing" }, { name: "women's clothing", id: 3, route: "/category/women's clothing" }, ]; useEffect(() => { // 初始化侧边栏实例 const sidenavElements = document.querySelectorAll('.sidenav'); const sidenavInstances = M.Sidenav.init(sidenavElements, { edge: 'left', draggable: true }); // 组件卸载时销毁实例 return () => { sidenavInstances.forEach(instance => instance.destroy()); } }, []); return ( <> <nav className='navMKY'> <div className='nav-wrapper'> <Link to='/' className='brand-logo'> <img src={logo} className="App-logo2" alt="logo" /> </Link> <Link to="#!" data-target="mobile-demo" className='sidenav-trigger'> <i className='material-icons'>menu</i> </Link> <ul className='right hide-on-med-and-down'> <li><Link to="/">Index</Link></li> { categories.map((category) => ( <li key={category.id}> <NavLink to={category.route}>{category.name}</NavLink> </li> )) } <li><Link to="/cart"> <Cart NumberSell={5}/></Link></li> </ul> </div> </nav> <ul className='sidenav red ' id="mobile-demo"> {/* 补充li标签包裹logo,符合Materialize侧边栏DOM结构规范 */} <li> <Link to='/' className='brand-logo'> <img src={logo} className="App-logo2" alt="logo" /> </Link> </li> <li><Link to="/">Index</Link></li> { categories.map((category) => ( <li key={category.id}> <NavLink to={category.route}>{category.name}</NavLink> </li> )) } <li><Link to="/cart"> <Cart NumberSell={5}/></Link></li> </ul> </> ); } export default Navbar;
小提示:如果需要点击侧边栏导航项后自动收起侧边栏,可以给NavLink增加点击事件,调用实例的
close()方法即可。
内容的提问来源于stack exchange,提问作者Juan Pablo Grover Pinto
相关产品推荐
相关产品推荐

