🐸 青蛙编程网
首页 / 前端 / React / 6. 列表渲染与条件渲染

6. 列表渲染与条件渲染

这是什么:列表与条件渲染 = 在 JSX 里用 map 生成列表、用三元或 && 决定某段 UI 要不要显示。

为什么用:上一章的页面写死着一条内容,真正实用的页面得能列出一堆数据、还得按情况显示或隐藏,JSX 里写 JS 正好顺手。

如何用:本章先把任务数组用 map 渲染成列表并补上 key,再做一个筛搜页,最后在一个页里把三种条件写法一次跑通。

6.1 列表:map 一把梭

整段可跑:

<!DOCTYPE html>
<html lang='zh-CN'>
<head>
  <meta charset='utf-8'>
  <script src='https://registry.npmmirror.com/react/18.3.1/files/umd/react.production.min.js'></script>
  <script src='https://registry.npmmirror.com/react-dom/18.3.1/files/umd/react-dom.production.min.js'></script>
  <script src='https://registry.npmmirror.com/@babel/standalone/7.29.11/files/babel.min.js'></script>
</head>
<body>
  <div id='root'></div>

  <script type='text/babel' data-presets='react'>
    function App() {
      const tasks = [
        { id: 1, text: '学 React', done: false },
        { id: 2, text: '写教程', done: true }
      ]

      return (
        <ul>
          {tasks.map((task) => (
            <li key={task.id}>{task.done ? '✅ ' : '⬜ '}{task.text}</li>   // key 用稳定 id,别用下标
          ))}
        </ul>
      )
    }

    ReactDOM.createRoot(document.getElementById('root')).render(<App />)
  </script>
</body>
</html>

你会看到:「⬜ 学 React」「✅ 写教程」两条列表。

两个关键点:

  1. arr.map() 返回一串 JSX,插进 { } 即可
  2. key 必须,让 React 认得「同一行」(用稳定 id,别用 index——中途插入会错乱)

6.2 条件渲染:三元与 && 当场各跑各

整段可跑,三种姿势一次看全(「提前 return」写在读法说明里):

<!DOCTYPE html>
<html lang='zh-CN'>
<head>
  <meta charset='utf-8'>
  <script src='https://registry.npmmirror.com/react/18.3.1/files/umd/react.production.min.js'></script>
  <script src='https://registry.npmmirror.com/react-dom/18.3.1/files/umd/react-dom.production.min.js'></script>
  <script src='https://registry.npmmirror.com/@babel/standalone/7.29.11/files/babel.min.js'></script>
</head>
<body>
  <div id='root'></div>

  <script type='text/babel' data-presets='react'>
    function App() {
      const [isLogin, setIsLogin] = React.useState(true)
      const [unread, setUnread] = React.useState(3)

      return (
        <div>
          <h2>{isLogin ? '欢迎回来 👋' : '请先登录'}</h2>          {/* ① 三元:二选一 */}
          <button onClick={() => setIsLogin(!isLogin)}>
            {isLogin ? '退出登录' : '去登录'}
          </button>

          {unread > 0 && <span>✉️ 未读 {unread}</span>}          {/* ② && 短路:有才渲染 */}
          <button onClick={() => setUnread(0)}>把未读清零试试</button>

          <hr />
          <p>关键词:{unread === 0 ? '未读清空' : '还有未读'}</p>   {/* ③ 放心嵌三元 */}
        </div>
      )
    }

    ReactDOM.createRoot(document.getElementById('root')).render(<App />)
  </script>
</body>
</html>

你会看到:「欢迎回来 + 未读 3」,点「退出登录」整句变「请先登录」(三元切换),点「清零」徽标直接消失不再渲染——0 坑的防法就在这里:写 unread > 0 && 而不是 unread &&。

第三种姿势「提前 return」是整个函数分支:在 return 前先判 if (loading) return <p>加载中…</p>,走不到的正常分支再返回整页——适合 loading / error / 正常这类整页级分支。

三者场景:

姿势 适用
三元 A 或 B 互斥
&& 只有「显示 A 或不显示」
提前 return 整页分支(loading / error / 正常)

头号大坑:&& 左侧是数字时小心 0:{cnt && <Badge/>} 当 cnt=0 会渲染出「0」字样。安全写法:{cnt > 0 && <Badge/>}。

6.3 筛一筛再展示:filter + map 组合拳

「搜一筛一展示」的真实页面,整段可跑:

<!DOCTYPE html>
<html lang='zh-CN'>
<head>
  <meta charset='utf-8'>
  <script src='https://registry.npmmirror.com/react/18.3.1/files/umd/react.production.min.js'></script>
  <script src='https://registry.npmmirror.com/react-dom/18.3.1/files/umd/react-dom.production.min.js'></script>
  <script src='https://registry.npmmirror.com/@babel/standalone/7.29.11/files/babel.min.js'></script>
</head>
<body>
  <div id='root'></div>

  <script type='text/babel' data-presets='react'>
    function App() {
      const tasks = [
        { id: 1, text: '学 React', done: false },
        { id: 2, text: '写教程', done: true },
        { id: 3, text: '跑步三公里', done: false }
      ]
      const [keyword, setKeyword] = React.useState('')

      const list = tasks
        .filter((t) => t.text.includes(keyword))   // 筛
        .filter((t) => !t.done)                    // 只要未完成

      return (
        <div>
          <input
            placeholder='搜任务'
            value={keyword}
            onChange={(e) => setKeyword(e.target.value)}
          />
          {list.length === 0 && <p>没有匹配任务</p>}
          <ul>
            {list.map((t) => <li key={t.id}>{t.text}</li>)}
          </ul>
        </div>
      )
    }

    ReactDOM.createRoot(document.getElementById('root')).render(<App />)
  </script>
</body>
</html>

你会看到:默认两条未完成任务;输入「跑」只剩一条;输入「写」什么都不显示(写教程已完成),换成「没有匹配任务」。

先纯 JS 筛好数据,再 map 出 UI——数据和视图解耦,代码慢慢读都不乱。

6.4 动手改

  1. 给 6.3 加第二个筛选:「只看已完成」(切换布尔,filter 一行换 t.done)
  2. 列表为空时显示emoji空状态,替换「没有匹配任务」
  3. 渲染商品数组,价格超出 100 的加 <em>贵</em> 标记

6.5 小结

  • 列表 = map + key(稳定 id 苦口婆心)
  • 条件 = 三元 / &&(注意 0)/ 提前 return
  • 先把数据处理干净,再一口气 map 出 JSX

下一章:组件通信:props 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。