2、前端基础(一):React核心概念(JSX、组件、Props、State)、创建第一个React应用

好,咱们正式开始前端部分。说实话,很多同学学全栈最怕的就是前端,觉得又要学HTML又要学CSS还要学JS,头都大了。但React的出现,其实把前端开发的门槛降了一大截。你想想看,以前写个页面要手动操作DOM,改个数据得先找到元素再更新,麻烦得很。React直接告诉你:别管DOM了,你只管数据,剩下的交给我。

我个人习惯把React理解成一个「状态机」。你的页面长什么样,完全取决于当前的数据状态。数据变了,页面自动跟着变。这个思路一旦建立起来,后面学什么都会顺很多。

JSX:在JavaScript里写HTML

先说说JSX。这东西刚出来的时候争议挺大的,很多人觉得「这不就是把HTML混进JS里了吗?开倒车啊!」。但我第一次用的时候,反而觉得挺自然。你想想,一个按钮的样式、行为、结构本来就是一体,硬拆成三个文件才奇怪吧?

JSX其实就是JavaScript的语法扩展。它允许你在JS文件里写类似HTML的标签:

const element = <h1>Hello, React!</h1>;

看着像HTML,但本质上是JS。浏览器不认识JSX,所以需要Babel这类工具把它转成 React.createElement() 调用。不过这些底层细节你暂时不用操心,脚手架都帮你配好了。

核心规则:JSX里只能有一个根元素。如果有多个并列标签,必须用 <div> 或者 <React.Fragment>(简写 <></>)包起来。

还有几个小细节要注意:

  • class 要写成 className(因为class是JS保留字)
  • style 接收一个对象,不是字符串:style={{ color: 'red' }}
  • 花括号 {} 里可以写任何JS表达式

我的习惯:刚开始写JSX时,容易忘记花括号。记住一个口诀:遇到JS逻辑就加花括号。变量、函数调用、三元表达式,统统包进去。

组件:页面的积木块

组件是React的核心思想。说白了,就是把页面拆成一个个独立的小块,每个块只管自己的事。我做过一个后台管理系统,光表格就有七八种变体。如果每个页面都单独写一遍,维护起来简直是噩梦。后来我把表格抽成组件,传不同的配置进去就行,省了至少一半的代码量。

React里组件有两种写法:

函数组件(推荐):

function Welcome(props) {
  return <h1>你好,{props.name}</h1>;
}

类组件(旧写法):

class Welcome extends React.Component {
  render() {
    return <h1>你好,{this.props.name}</h1>;
  }
}

现在新项目基本都用函数组件了。类组件你了解就行,面试偶尔会问到,但实际开发中我建议直接用函数组件加Hooks。

注意:组件名必须大写开头。React会区分小写开头的标签(原生HTML)和大写开头的标签(自定义组件)。我见过新手因为这个bug排查了半天,嗯,我自己也犯过。

Props:组件之间的传话筒

Props就是组件的参数。父组件给子组件传数据,全靠它。而且Props是只读的——你绝对不能在里面修改props的值。为什么?因为数据流是单向的,从父到子,改数据只能由父组件来做。

// 父组件
function App() {
  return <User name="张三" age={25} />;
}

// 子组件
function User(props) {
  return (
    <div>
      <p>姓名:{props.name}</p>
      <p>年龄:{props.age}</p>
    </div>
  );
}

这里有个小技巧:可以用解构让代码更清爽:

function User({ name, age }) {
  return (
    <div>
      <p>姓名:{name}</p>
      <p>年龄:{age}</p>
    </div>
  );
}

避坑指南:我曾经在项目里把props直接赋值给state,结果数据不同步了。记住,props是父组件的数据快照,不要试图在子组件里「缓存」它,除非你真的知道自己在做什么。

State:让组件活起来

Props是外部传入的,State是组件自己管理的。State变了,组件自动重新渲染。这就是React最核心的「响应式」机制。

在函数组件里,我们用 useState 这个Hook来管理状态:

import { useState } from 'react';

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

  return (
    <div>
      <p>你点击了 {count} 次</p>
      <button onClick={() => setCount(count + 1)}>点我</button>
    </div>
  );
}

注意几个要点:

  • useState 返回一个数组,第一个是当前值,第二个是更新函数
  • 更新State要用set函数,直接修改count不会触发重新渲染
  • State更新是异步的,连续调用setCount(count + 1)两次,只会加一次

为什么是异步?React会把多个setState合并成一次更新,提高性能。所以如果你依赖前一个状态来更新,要用函数形式:setCount(prev => prev + 1)

创建第一个React应用

好,理论说完了,咱们动手创建一个真正的React项目。我建议用Vite,比Create React App快得多:

npm create vite@latest my-first-react-app -- --template react
cd my-first-react-app
npm install
npm run dev

几秒钟后,浏览器打开 http://localhost:5173,你就能看到React的默认页面了。

项目结构很简单:

文件/目录 作用
src/main.jsx 入口文件,渲染根组件
src/App.jsx 根组件,你主要在这里写代码
src/App.css 样式文件
index.html HTML模板,Vite会注入JS

打开 src/App.jsx,把里面的内容替换成我们刚才写的Counter组件:

import { useState } from 'react';
import './App.css';

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

  return (
    <div className="App">
      <h1>我的第一个React应用</h1>
      <p>你点击了 {count} 次</p>
      <button onClick={() => setCount(count + 1)}>
        点我
      </button>
    </div>
  );
}

export default App;

保存文件,浏览器会自动刷新。点击按钮,数字就会变化。恭喜你,第一个React应用跑起来了!

我的建议:刚开始别急着学太多API。先把JSX、组件、Props、State这四个概念玩熟。我见过太多人一上来就啃Redux、React Router,结果基础没打牢,后面越学越乱。先把Counter改成Todo List,再改成留言板,一步步来。

嗯,这一章的内容就到这。下一章我们会深入React的组件通信和生命周期,到时候你会发现自己对React的理解又上了一个台阶。