大家好啊!今天咱们来聊聊 React—— 这个现在前端圈超火的库。不管你是刚入门前端的小白,还是想转行学开发的新手,只要想做界面开发,React 几乎是绕不开的坎。别担心,今天我就用最接地气的话,把 React 每天要用的 80% 核心知识点讲透,每个点都配代码,保证你看完就懂,懂了就能用!

一、创建和嵌套组件:React 的 “积木块”

咱们先从最基础的说起:组件。你可以把组件理解成 UI 的 “积木”,小到一个按钮,大到一整个页面,都是组件拼出来的。

重点总结:

  • 组件是返回标签的 JavaScript 函数
  • 组件名必须以大写字母开头(区分 HTML 标签)
  • 组件可以像积木一样嵌套使用

咱们来看个例子,先创建一个按钮组件:

function MyButton() {
  return (
    <button>I'm a button</button>
  );
}

这个MyButton就是个最简单的组件,它是个函数,返回了一个按钮标签。注意哦,函数名MyButton是大写开头的,这是规矩,要是写成小写myButton,React 就不认识它是组件了。

那怎么用这个组件呢?可以把它嵌套到另一个组件里,比如整个应用的根组件:

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />  {/* 嵌套刚才创建的MyButton组件 */}
    </div>
  );
}

这里的export default是说,MyApp是这个文件里的 “主角” 组件,其他地方导入这个文件时,默认拿到的就是它。

你看,这样就像搭积木一样,用<MyButton />把按钮组件拼到了MyApp里,运行起来就会显示 “Welcome to my app” 和一个按钮。是不是很简单?

二、用 JSX 写标签:React 的 “专属语法”

刚才写的<button><div>这种标签,其实不是 HTML,而是JSX语法。它是 React 推荐的写标签的方式,虽然不是必须的,但用起来是真方便。

重点总结:

  • JSX 是 React 里写标签的语法,融合了 JS 和 HTML
  • 必须闭合所有标签(比如<br />不能写成<br>
  • 组件不能返回多个 JSX 标签,必须用一个父级包起来(比如<div><>

JSX 比 HTML 严格多了。比如 HTML 里<img src="xxx">可以不闭合,但 JSX 里必须写成<img src="xxx" />。再比如,一个组件想返回多个标签,直接写是不行的:

// 错误示例:不能返回多个标签
function AboutPage() {
  return (
    <h1>About</h1>
    <p>Hello there.</p>  {/* 这里会报错! */}
  );
}

这时候就得找个 “容器” 把它们包起来。可以用<div>

function AboutPage() {
  return (
    <div>  {/* 用div当容器 */}
      <h1>About</h1>
      <p>Hello there.<br /></p>  {/* <br />必须闭合 */}
    </div>
  );
}

要是不想多一个<div>(有时候会影响样式或布局),可以用空标签<>(也叫 Fragment):

function AboutPage() {
  return (
    <>  {/* 空标签当容器,不产生额外DOM */}
      <h1>About</h1>
      <p>Hello there.<br /></p>
    </>
  );
}

这样既满足了 “一个父级” 的要求,又不会多出来没用的标签,完美!

如果手里有一堆 HTML 想转成 JSX,不用手动改,网上有现成的在线转换器,复制粘贴就行,超方便。

三、给组件加样式:让界面变好看

写好了结构,接下来就得打扮打扮组件了。React 里加样式的方式和 HTML 很像,但有一点点区别。

重点总结:

  • className指定 CSS 类(相当于 HTML 的class
  • 可以用style属性写行内样式,适合依赖 JS 变量的情况
  • CSS 文件该怎么引入还怎么引入(比如用<link>标签)

先看用 CSS 类的方式。比如想给图片加个圆形边框,先在 JSX 里用className定义类名:

<img className="avatar" />  {/* 注意是className,不是class */}

然后在 CSS 文件里写样式:

/* 比如叫style.css */
.avatar {
  border-radius: 50%;  /* 圆形边框 */
}

最后在 HTML 里用<link>引入这个 CSS 文件就行,和普通网页一样。

那如果样式需要根据 JS 变量动态变化呢?这时候就用style属性。比如图片大小由变量imageSize决定:

const user = {
  name: 'Hedy Lamarr',
  imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
  imageSize: 90,  // 图片大小
};

function Profile() {
  return (
    <>
      <h1>{user.name}</h1>
      <img
        className="avatar"  // 用CSS类
        src={user.imageUrl}
        alt={'Photo of ' + user.name}
        style={{  // 行内样式,注意是双大括号
          width: user.imageSize,  // 依赖JS变量
          height: user.imageSize
        }}
      />
    </>
  );
}

这里的style={{}}其实是style={}(JSX 大括号)里面包了一个普通的 JS 对象{},所以是双大括号。这种方式适合样式跟着变量变的场景,比如根据状态改颜色、大小等。

四、显示数据:让 JS 和标签 “互动”

React 的一大优势就是能轻松把 JS 里的数据显示到界面上。秘诀就是用大括号{}—— 在 JSX 里,大括号就像一个 “通道”,能把 JS 变量或表达式 “送” 到标签里。

重点总结:

  • {变量名}在 JSX 中显示数据
  • 属性里用{}而不是引号(引号里是字符串,{}里是 JS 表达式)
  • 大括号里可以写任何 JS 表达式(比如字符串拼接、运算等)

比如想显示用户名字,直接把user.name放进大括号:

return <h1>{user.name}</h1>;  // 显示user对象的name属性

如果是标签的属性,比如图片的src,也用大括号:

// 正确:用{}引用JS变量
<img src={user.imageUrl} />

// 错误:引号里的是字符串,不会解析变量
<img src="user.imageUrl" />  {/* 会把"user.imageUrl"当字符串,显示不了图片 */}

大括号里还能写更复杂的表达式,比如字符串拼接:

alt={'Photo of ' + user.name}  // 拼接成"Photo of Hedy Lamarr"

甚至可以写运算,比如显示数字加 1:

<p>Count: {count + 1}</p>  // 如果count是3,就显示"Count: 4"

这样一来,JS 里的数据就能随时 “同步” 到界面上,特别灵活。

五、条件渲染:让界面 “看情况” 显示

有时候界面需要根据条件显示不同内容,比如用户登录了显示 “欢迎回来”,没登录显示 “请登录”。React 里没有专门的条件语法,直接用普通 JS 的 if、三元运算符就行。

重点总结:

  • 用 if 语句拆分不同条件的 JSX
  • 条件 ? 内容1 : 内容2在 JSX 内写条件
  • 条件 && 内容只在条件为真时显示内容

先看 if 语句的用法。比如根据isLoggedIn(是否登录)显示不同组件:

let content;  // 存储要显示的内容
if (isLoggedIn) {
  content = <AdminPanel />;  // 登录了显示管理面板
} else {
  content = <LoginForm />;  // 没登录显示登录表单
}

return <div>{content}</div>;  // 显示content

这种方式适合条件比较复杂的情况,逻辑清晰。

如果想写得更紧凑,可以用三元运算符,直接嵌在 JSX 里:

<div>
  {isLoggedIn ? (  // 条件
    <AdminPanel />  // 条件为真时显示
  ) : (
    <LoginForm />   // 条件为假时显示
  )}
</div>

这样不用单独定义变量,一行搞定。

还有一种更简单的情况:只在条件为真时显示内容,否则不显示。这时候用&&运算符:

<div>
  {isLoggedIn && <AdminPanel />}  // 只有isLoggedIn为真,才显示AdminPanel
</div>

原理是 JS 里true && 表达式会返回表达式,false && 表达式会返回 false,而 React 会忽略 false,所以不显示。

比如购物清单里,只给水果标上特殊颜色,就可以这么写:

const products = [
  { title: 'Cabbage', isFruit: false, id: 1 },
  { title: 'Garlic', isFruit: false, id: 2 },
  { title: 'Apple', isFruit: true, id: 3 },
];

function ShoppingList() {
  const listItems = products.map(product => (
    <li
      key={product.id}
      style={{
        color: product.isFruit ? 'magenta' : 'darkgreen'  // 三元运算符:水果是洋红色,蔬菜是深绿色
      }}
    >
      {product.title}
    </li>
  ));
  return <ul>{listItems}</ul>;
}

这里根据product.isFruit的真假,用三元运算符动态改颜色,是不是很灵活?

五、渲染列表:批量展示数据

网页里经常要显示列表(比如商品列表、评论列表),React 里渲染列表的关键是用 JS 的map()函数 —— 把数组里的每个元素转成 JSX 标签,再整体显示。

重点总结:

  • array.map()把数组转成 JSX 列表
  • 每个列表项必须有key属性,且唯一(通常用数据的 id)
  • key帮助 React 识别列表项的变化,提升性能

比如有个产品数组,想渲染成<li>列表:

const products = [
  { title: 'Cabbage', id: 1 },
  { title: 'Garlic', id: 2 },
  { title: 'Apple', id: 3 },
];

function ShoppingList() {
  // 用map把数组转成li标签数组
  const listItems = products.map(product => (
    <li 
      key={product.id}  // 必须有key,且唯一
    >
      {product.title}
    </li>
  ));
  return <ul>{listItems}</ul>;  // 显示列表
}

这里的key非常重要,它就像列表项的 “身份证”,React 靠它判断哪个项被添加、删除或修改了,从而高效更新界面。key必须在兄弟项之间唯一,最好用数据本身的 id(比如从数据库拿的 id),不要用数组索引(因为索引会变)。

再加点样式,让水果和蔬菜颜色不同(前面条件渲染的例子):

const products = [
  { title: 'Cabbage', isFruit: false, id: 1 },
  { title: 'Garlic', isFruit: false, id: 2 },
  { title: 'Apple', isFruit: true, id: 3 },
];

function ShoppingList() {
  const listItems = products.map(product => (
    <li
      key={product.id}  // 唯一key
      style={{
        color: product.isFruit ? 'magenta' : 'darkgreen'  // 动态颜色
      }}
    >
      {product.title}
    </li>
  ));
  return <ul>{listItems}</ul>;
}

这样渲染出来的列表,苹果是洋红色,白菜和大蒜是深绿色,清晰又直观。

六、响应事件:让组件 “有反应”

界面不能只是 “看” 的,还得能 “互动”—— 比如点击按钮、输入文字等。React 里通过事件处理函数来响应这些操作。

重点总结:

  • on事件名(比如onClick)绑定事件处理函数
  • 事件处理函数是普通 JS 函数,定义在组件内部
  • 绑定的时候不要加括号(onClick={handleClick},不是handleClick()

比如做个按钮,点击弹出提示:

function MyButton() {
  // 定义事件处理函数
  function handleClick() {
    alert('You clicked me!');  // 点击后执行
  }

  return (
    <button onClick={handleClick}>  // 绑定事件,注意没有括号
      Click me
    </button>
  );
}

这里的onClick是 React 的点击事件(注意首字母大写,和 HTML 的onclick不同),等号后面是事件处理函数handleClick特别注意:不要写成onClick={handleClick()}—— 加了括号会立即执行函数,而不是等点击的时候执行。

除了点击事件,还有onChange(输入变化)、onSubmit(表单提交)等,用法都一样:定义函数,然后绑定到on事件名上。比如输入框内容变化时打印值:

function MyInput() {
  function handleChange(e) {
    console.log('输入的是:', e.target.value);  // e是事件对象
  }

  return (
    <input
      type="text"
      onChange={handleChange}  // 输入变化时触发
    />
  );
}

这样每次输入文字,控制台都会打印当前输入的内容,轻松实现互动。

七、更新界面:让组件 “记住” 状态

很多时候,组件需要 “记住” 一些信息并更新界面 —— 比如按钮被点击了多少次。这时候就需要state(状态),它是组件内部的 “记忆”,状态变了,界面会自动更新。

重点总结:

  • useState声明状态变量(需要从 React 导入)
  • useState(初始值)返回两个东西:当前状态和更新状态的函数(比如[count, setCount]
  • 调用更新函数(比如setCount)会改变状态,并让组件重新渲染

先看个计数器的例子:点击按钮,次数加 1。步骤很简单:

  1. 从 React 导入useState

import { useState } from 'react';  // 第一步:导入

  1. 在组件里用useState声明状态变量:

function MyButton() {
  // 声明count状态,初始值是0
  // count是当前状态,setCount是更新它的函数
  const [count, setCount] = useState(0);

  1. 写事件处理函数,用setCount更新状态:

  function handleClick() {
    setCount(count + 1);  // 点击一次,count加1
  }

  1. 在 JSX 里显示count

  return (
    <button onClick={handleClick}>
      Clicked {count} times  // 显示当前次数
    </button>
  );
}

完整代码就是:

import { useState } from 'react';

function MyButton() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

运行后,每次点击按钮,count会加 1,界面上的次数也会跟着变。这就是 state 的魔力:状态变了,React 会自动重新渲染组件,让界面展示最新的状态。

更厉害的是,每个组件的 state 都是独立的。比如渲染两个MyButton

export default function MyApp() {
  return (
    <div>
      <MyButton />
      <MyButton />
    </div>
  );
}

点击第一个按钮,只有第一个的次数会增加;点击第二个,只有第二个的次数会增加 —— 它们各记各的,互不影响。

八、使用 Hook:React 的 “功能插件”

刚才用的useState其实是一个Hook(钩子)。Hook 是 React 里一类特殊的函数,能让组件拥有各种功能(比如 state、副作用等),名字都以use开头。

重点总结:

  • Hook 是 React 的功能函数,以use开头(如useStateuseEffect
  • 只能在组件的顶层调用 Hook(不能在 if、循环、函数嵌套里用)
  • 可以自己组合 Hook 创建自定义 Hook

useState是最常用的内置 Hook,用来管理状态。还有个常用的useEffect,用来处理副作用(比如请求数据、设置定时器),不过这里先不展开,知道有这么个东西就行。

使用 Hook 有个严格的规则:只能在组件的顶层调用,不能在条件、循环或嵌套函数里用。比如下面的代码是错误的:

// 错误示例:在if里调用useState
function MyComponent() {
  if (someCondition) {
    const [count, setCount] = useState(0);  // 不行!
  }
  // ...
}

为什么呢?因为 React 靠 Hook 的调用顺序来管理它们,如果在条件里调用,顺序会乱,导致 bug。如果确实需要条件判断,就把 Hook 提到条件外面,或者拆分成新组件。

除了内置 Hook,还能自己写自定义 Hook,把重复的逻辑抽出来。比如多个组件都需要 “记录点击次数” 的功能,就可以写个useCounter Hook:

import { useState } from 'react';

// 自定义Hook,以use开头
function useCounter(initialValue) {
  const [count, setCount] = useState(initialValue);
  
  function increment() {
    setCount(count + 1);
  }
  
  return [count, increment];  // 返回状态和更新函数
}

// 使用自定义Hook
function MyButton() {
  const [count, increment] = useCounter(0);  // 复用逻辑
  
  return (
    <button onClick={increment}>
      Clicked {count} times
    </button>
  );
}

这样一来,任何组件想实现计数器功能,直接用useCounter就行,不用重复写useStateincrement逻辑了,特别方便。

九、组件间共享数据:让组件 “协同工作”

有时候多个组件需要共享数据,比如两个按钮,点击任何一个,两个按钮显示的次数都一起增加。这时候就需要状态提升—— 把共享的状态放到它们共同的父组件里,再通过 props 传递给子组件。

重点总结:

  • 状态提升:子组件的状态移到父组件,通过 props 传递给子组件
  • props 是父组件传递给子组件的数据 / 函数,子组件通过参数接收
  • 子组件通过调用父组件传递的函数,间接更新父组件的状态

还用计数器的例子,现在要两个按钮共享一个 count,点击任何一个,次数一起增加。步骤如下:

  1. 把状态从子组件MyButton移到父组件MyApp

import { useState } from 'react';

export default function MyApp() {
  // 父组件里声明状态
  const [count, setCount] = useState(0);

  // 父组件里定义更新函数
  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>Counters that update together</h1>
      {/* 把count和handleClick传给子组件 */}
      <MyButton count={count} onClick={handleClick} />
      <MyButton count={count} onClick={handleClick} />
    </div>
  );
}

  1. 子组件MyButton通过参数接收父组件传递的countonClick(这些参数叫 props):

// 子组件接收props
function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>  // 调用父组件的函数
      Clicked {count} times  // 显示父组件传递的count
    </button>
  );
}

这样一来,两个MyButtoncount都来自父组件的count,点击时调用的都是父组件的handleClick,所以不管点哪个,父组件的count都会增加,两个按钮显示的次数也会一起更新。

这种 “状态提升” 是 React 中组件共享数据的核心方式:共享的数据放在共同的父组件,子组件通过 props 获取数据和更新方法,实现协同工作。

总结:React 入门就这么点事儿

看到这里,你已经掌握了 React 日常开发中 80% 的知识点:从创建组件、写 JSX 标签,到加样式、显示数据,再到处理事件、管理状态、共享数据,一套流程走下来,基本能写个简单的 React 应用了。

可能一开始会觉得 JSX、state、props 这些概念有点绕,但多写几个例子就会发现,它们其实都是为了让 “数据” 和 “界面” 更好地配合。组件就像积木,state 是记忆,props 是桥梁,事件是互动的开关,把这些串起来,就能搭出各种复杂的界面。

接下来建议你找个小项目练练手,比如 todo 列表、计数器、简单的表单,把这些知识点用起来。用着用着就会发现,React 其实没那么难,甚至还挺有趣的!

如果想深入学习,可以看看 React 官方文档的 “实战教程”,或者研究更复杂的 Hook(比如useEffectuseContext),但入门阶段,把今天讲的这些吃透,就足够应付大部分场景了。加油,祝你在 React 的路上越走越顺!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐