You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用React组件替代HTML字符串实现带Link的字母分类导航网格?

问题

我之前通过构建HTML字符串并使用dangerouslySetInnerHTML渲染来创建导航网格,但现在需要用react-router-dom的Link组件替代<a>标签,不再使用HTML字符串。示例是<Link to={item.path}>{item.name}</Link>。

我之前的实现代码如下:

import React, { Fragment } from 'react'; 
import { Link } from 'react-router-dom'; 

const Menu = props => { 
  const sortedList = props.list.sort((a,b) => (a.name < b.name) ? -1 : (a.name > b.name) ? 1 : 0); 

  const mapToAlphaGrid = () => { 
    const cap = '</div>'; 
    const max = sortedList.length; 
    let lastChar=""; 
    let row = '<div class="row">'; 
    let col = '<div class="grid-col col-4">'; 
    let html = row; 
    let isCap = false; 

    for(var i=0; i < max; i++ ){ 
      let item = sortedList[i]; 
      let char = item.name.charAt(0); 

      if(char > lastChar){ 
        let alphaTitle = `<div class="alpha-title">${char}</div>` 
        html += isCap ? cap + col + alphaTitle : col + alphaTitle; 
        isCap = true; 
      } 
      html += `<a class="link" href=${item.path}>${item.name}</a>`; 
      lastChar = char; 

      if(i >= max-1){ 
        return html + cap + cap; 
      } 
    } 
  } 

  return( 
    <div dangerouslySetInnerHTML={{ __html: mapToAlphaGrid() }} /> 
  ) 
} 

export default Menu;

我希望用React组件实现上述网格(部分列包含多个Link组件),请问该如何实现?


回答

嘿,这事儿不难!核心就是把之前拼接HTML字符串的逻辑,改成生成React元素数组的方式,彻底抛弃dangerouslySetInnerHTML——既安全,又完全符合React的组件化思路。我给你重写了代码,还优化了分组逻辑,比原来的循环更清晰:

import React from 'react';
import { Link } from 'react-router-dom';

const Menu = ({ list }) => {
  // 先对列表按名称排序,用扩展运算符避免修改原数组
  const sortedList = [...list].sort((a, b) => a.name.localeCompare(b.name));

  // 用reduce把列表按首字母分组,统一转大写避免大小写分组混乱
  const groupedByLetter = sortedList.reduce((groups, item) => {
    const firstChar = item.name.charAt(0).toUpperCase();
    if (!groups[firstChar]) {
      groups[firstChar] = [];
    }
    groups[firstChar].push(item);
    return groups;
  }, {});

  // 渲染网格:每3个字母组为一行(对应col-4的布局)
  const renderGrid = () => {
    const letters = Object.keys(groupedByLetter);
    const gridRows = [];

    // 按每行3列拆分字母组
    for (let i = 0; i < letters.length; i += 3) {
      const rowColumns = [];
      // 处理当前行的列(最多3个)
      for (let j = i; j < i + 3 && j < letters.length; j++) {
        const letter = letters[j];
        const items = groupedByLetter[letter];
        
        // 渲染单个列:包含字母标题和对应的Link组件列表
        const column = (
          <div key={letter} className="grid-col col-4">
            <div className="alpha-title">{letter}</div>
            {items.map(item => (
              <Link key={item.path} to={item.path} className="link">
                {item.name}
              </Link>
            ))}
          </div>
        );
        rowColumns.push(column);
      }

      // 把当前行加入结果数组
      gridRows.push(
        <div key={`row-${i}`} className="row">
          {rowColumns}
        </div>
      );
    }
    return gridRows;
  };

  return <div className="menu-grid">{renderGrid()}</div>;
};

export default Menu;

代码说明:

  1. 分组优化:用reduce把排序后的列表按首字母分组,比原来的循环拼接逻辑更易读、易维护,还加了首字母大写处理,避免"A"和"a"分成两组的问题。
  2. 组件化渲染:不再拼接字符串,而是直接生成React元素——每个列是一个div,里面包含字母标题和多个Link组件,完全符合React的渲染规范。
  3. 布局适配:按照你原来的col-4布局(每行3列),把字母组按每3个拆分成一行,和原来的HTML结构效果完全一致。
  4. 安全合规:彻底移除了dangerouslySetInnerHTML,避免了XSS风险,也能正常使用React的所有特性(比如组件状态、生命周期等)。

如果你的首字母不需要统一大写,直接去掉.toUpperCase()就行啦!

内容的提问来源于stack exchange,提问作者me-me

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:09:18