一、JSX 基础与项目创建
如果你有过vue或者其他框架的经验,那你肯定对组件这个知识有一定的了解,在react,组件就是通过jsx来写的(本文主要是函数式组件)
举个最简单的jsx的例子:
jsx
function App() {
return (
<div className="App">
<header className="App-header">
<h1>Hello, React!</h1>
</header>
</div>
);
}
对于jsx,最简单粗暴的就是,在函数的return值里面写html,其中这个html通过()进行包裹 ,其他的数据处理放置在函数的函数体(return之前)
下面我们正式开始react项目的书写
首先,我们要创建react的项目工程,这里提供两种方式:
方式一:通过官方脚手架创建
bash
npx create-react-app my-app
方式二:通过vite
bash
npm create vite
# 之后在选择模板的时候直接选择react即可
其实更推荐使用pnpm,无他,就是快
创建好之后,我们进入目录,装好依赖就可以开始写我们的react代码了:
bash
npm install
二、React 基础语法:
1、模板语法:
jsx
function App() {
const name = "Hello World!!!"
return (
<div className="App">
<header className="App-header">
<h1>
{name} {/*通过大括号包裹就可以在页面中渲染出name的值*/}
</h1>
</header>
</div>
);
}
2、注释
在函数体使用注释和js使用注释一致,不在过多的讲述
在标签内部如何使用呢?
jsx
function App() {
const name = "Hello World!!!"
return (
<div className="App">
<header className="App-header">
{/* 这是 JSX 内部的单行注释 */}
{/*
这是 JSX 内部的
多行注释
*/}
<h1>
{name} {/*通过大括号包裹就可以在页面中渲染出name的值*/}
</h1>
</header>
</div>
);
}
三、在react中实现vue的各种功能
1、实现类似vue的各种指令(v-if,v-for...)
react中并没有提供各种指令,但是,我们依旧也是可以实现的
(1)v-if
/ v-else
/ v-else-if
(条件渲染)
Vue 中通过指令控制元素是否渲染;React 中通过JavaScript 条件表达式(三目运算、逻辑与、if 语句)实现。
vue:
vue
<div>
<p v-if="type === 'a'">A</p>
<p v-else-if="type === 'b'">B</p>
<p v-else>Other</p>
</div>
react:
jsx
function MyComponent({ type }) {
// 方式1:三目运算符(适合简单分支)
return (
<div>
{type === 'a' ? <p>A</p> :
type === 'b' ? <p>B</p> :
<p>Other</p>}
</div>
);
// 方式2:if 语句(适合复杂逻辑)
// let content;
// if (type === 'a') content = <p>A</p>;
// else if (type === 'b') content = <p>B</p>;
// else content = <p>Other</p>;
// return <div>{content}</div>;
}
通俗来讲就是使用if表达式
来条件性的渲染,你可以直接在if-else
体内return你要渲染的部分,注意要使用{}
进行包裹
(2)v-show
(显示 / 隐藏元素)
Vue 中通过 display: none
控制元素显示;React 中直接通过动态 style 或类名控制。
Vue :
vue
<p v-show="isVisible">会被隐藏的文本</p>
react:
jsx
function MyComponent({ isVisible }) {
return (
// 方式1:通过 style 控制 display
<p style={{ display: isVisible ? 'block' : 'none' }}>
会被隐藏的文本
</p>
// 方式2:通过类名(配合 CSS)
// <p className={isVisible ? 'visible' : 'hidden'}>文本</p>
// CSS: .hidden { display: none; } .visible { display: block; }
);
}
(3)v-for
(列表渲染)
Vue 中通过指令遍历数组;React 中通过数组的 map 方法 实现,需手动添加 key
(类似 Vue 的 :key
)。
vue:
vue
<ul>
<li v-for="(item, index) in list" :key="index">
{{ item.name }}
</li>
</ul>
react:
jsx
function MyComponent({ list }) {
return (
<ul>
{list.map((item, index) => (
<li key={index /* 推荐用唯一ID,如item.id */}>
{item.name}
</li>
))}
</ul>
);
}
(4)v-bind
(属性绑定)
Vue 中通过 v-bind:xxx
绑定属性;React 中直接在 JSX 中用大括号 {} 绑定。
vue:
vue
<img v-bind:src="imgUrl" v-bind:alt="imgAlt" />
<!-- 简写 -->
<img :src="imgUrl" :alt="imgAlt" />
react:
jsx
function MyComponent({ imgUrl, imgAlt }) {
return <img src={imgUrl} alt={imgAlt} />;
}
注意:React 中部分属性名与 HTML 不同(如 className 对应 class,htmlFor 对应 for)。
(5)v-on
(事件绑定)
Vue 中通过 v-on:xxx
绑定事件;React 中通过 onXxx
驼峰命名法 绑定,事件处理函数直接传入。
vue:
vue
<button v-on:click="handleClick">点击</button>
<!-- 简写 -->
<button @click="handleClick">点击</button>
react:
jsx
function MyComponent() {
const handleClick = () => {
console.log('点击了');
};
return <button onClick={handleClick}>点击</button>;
}
(6)v-model
(双向绑定)
Vue 中 v-model
是 value
+ input
事件的语法糖;React 中需手动实现「状态绑定 + 事件更新」
如果你完全没了解过react,那么我建议你先去看完下一节实现ref和reactive数据响应式
再看这个
vue:
vue
<input v-model="username" />
<p>输入的内容:{{ username }}</p>
react:
jsx
import { useState } from 'react';
function MyComponent() {
// 1. 用 state 存储值
const [username, setUsername] = useState('');
// 2. 定义事件处理函数更新 state
const handleChange = (e) => {
setUsername(e.target.value);
};
// 3. 绑定 value 和 onChange
return (
<div>
<input value={username} onChange={handleChange} />
<p>输入的内容:{username}</p>
</div>
);
}
2、在react中实现类似vue的 ref
和reactive
的数据响应式:
React 的 useState
可以很简洁地实现类似 Vue 中 ref
的响应式功能。核心思路是:用 useState
存储数据,通过状态更新函数触发视图刷新,达到数据变化自动更新 UI 的效果:
jsx
// 和vue一样需要导入
import { useState } from 'react';
function Counter() {
// 1. 调用useState,初始值为0
// 返回 [当前计数, 更新计数的函数],用数组解构获取
const [count, setCount] = useState(0);
return (
<div>
{/* 显示当前状态 */}
<p>当前计数:{count}</p>
{/* 点击按钮时,调用更新函数修改状态 */}
<button onClick={() => setCount(count + 1)}>
+1
</button>
</div>
);
}
export default Counter;
在react中实现数据响应式麻烦一点,需要你手动的调用更新函数去更新页面才会更新,在react中这叫状态管理
,而类似的useState
叫Hook
3、父子组件之间传递数据:Props 传递
父组件通过属性(props)把数据传给子组件。子组件通过 props
接收,若要修改,需调用父组件传过来的更新函数。跟vue的比较像
jsx
// 父组件
function Parent() {
const [name, setName] = useState("小明");
return (
<div>
<Child name={name} onNameChange={(newName) => setName(newName)} />
</div>
);
}
// 子组件
function Child({ name, onNameChange }) {
return (
<div>
<p>姓名:{name}</p>
<button onClick={() => onNameChange("小红")}>改名</button>
</div>
);
}
4、react中实现全局状态管理
当多个组件(跨层级、非父子)需要共享数据(如用户信息、购物车、主题设置),可以用:
- useContext + useReducer:React 内置方案,适合中小型应用。
- 第三方库:如 Redux、Zustand、Jotai 等,适合大型应用。
这里主要演示第一种,第三方库的可以自行了解或者有需要后期出教程
jsx
// 1. 创建上下文
const ThemeContext = createContext();
// 2. 顶层组件提供数据
function App() {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Header />
<Content />
</ThemeContext.Provider>
);
}
// 3. 任意子组件使用数据
function Header() {
const { theme } = useContext(ThemeContext);
return <div>当前主题:{theme}</div>;
}
5、react中的事件处理:
React 的事件处理机制与原生 JavaScript 类似,但有一些语法和行为上的差异,在给标签绑定事件的时候,采用驼峰命名法(如 onClick
而非 onclick
)
jsx
import { useState } from 'react';
function EventExamples() {
const [message, setMessage] = useState('');
const [coords, setCoords] = useState({ x: 0, y: 0 });
const [isHovered, setIsHovered] = useState(false);
// 1. 点击事件 (onClick)
const handleClick = () => {
alert('按钮被点击了!');
};
// 2. 输入框变化事件 (onChange)
const handleInputChange = (e) => {
setMessage(e.target.value);
};
// 3. 键盘按下事件 (onKeyDown)
const handleKeyDown = (e) => {
if (e.key === 'Enter') {
alert(`你输入了:${message}`);
}
};
// 4. 鼠标移动事件 (onMouseMove)
const handleMouseMove = (e) => {
setCoords({
x: e.clientX,
y: e.clientY
});
};
// 5. 鼠标悬停/离开事件 (onMouseEnter / onMouseLeave)
const handleMouseEnter = () => {
setIsHovered(true);
};
const handleMouseLeave = () => {
setIsHovered(false);
};
// 6. 表单提交事件 (onSubmit)
const handleSubmit = (e) => {
e.preventDefault(); // 阻止默认提交行为
alert(`表单提交:${message}`);
};
return (
<div style={{ padding: 20 }}>
{/* 1. 点击事件 */}
<button onClick={handleClick}>点击我</button>
<br /><br />
{/* 2. 输入框变化 + 3. 键盘事件 */}
<input
type="text"
placeholder="输入内容,按回车确认"
value={message}
onChange={handleInputChange}
onKeyDown={handleKeyDown}
/>
<br /><br />
{/* 4. 鼠标移动事件 */}
<div
style={{ border: '1px solid #ccc', padding: 10, marginTop: 10 }}
onMouseMove={handleMouseMove}
>
移动鼠标查看坐标:
X: {coords.x}, Y: {coords.y}
</div>
<br />
{/* 5. 鼠标悬停/离开事件 */}
<div
style={{
width: 100,
height: 100,
backgroundColor: isHovered ? 'lightblue' : 'lightgray'
}}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{isHovered ? '鼠标在这' : '鼠标离开'}
</div>
<br />
{/* 6. 表单提交事件 */}
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="输入内容提交"
value={message}
onChange={handleInputChange}
/>
<button type="submit">提交</button>
</form>
</div>
);
}
export default EventExamples;
6、在react中获取dom实例
在 React 中获取 DOM 元素实例主要通过 useRef
钩子函数实现,这是官方推荐的方式。useRef
会创建一个可变的 ref
对象,其 .current
属性可以存储 DOM 元素的引用。
步骤:
useRef(null)
创建一个容器,用来存 DOM 元素- 通过
ref={myInput}
把 input 元素和这个容器绑定 - 用
myInput.current
就能拿到真实的 DOM 元素(如输入框) - 可以直接调用 DOM 方法(如
focus()
)或访问属性(如value
)
jsx
import { useRef, useEffect } from 'react';
function SimpleRef() {
// 1. 创建ref
const myInput = useRef(null);
// 2. 组件挂载后操作DOM
useEffect(() => {
// myInput.current 就是input的DOM元素
myInput.current.focus(); // 自动聚焦
}, []);
// 3. 点击按钮获取输入框值
const showValue = () => {
alert(myInput.current.value); // 直接访问DOM的value
};
return (
<div>
{/* 绑定ref到input */}
<input ref={myInput} placeholder="请输入..." />
<button onClick={showValue}>显示输入内容</button>
</div>
);
}
export default SimpleRef;
7、react的生命周期(主要通过用 useEffect
实现)
组件挂载时(初始化):
jsx
useEffect(() => {
console.log('组件挂载完成');
// 可做初始化操作(如请求数据、绑定事件)
}, []); // 空依赖数组:只执行一次
组件更新时(依赖变化):
jsx
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`count 变化了:${count}`);
// 依赖 count,只有 count 变了才执行
}, [count]); // 依赖数组:指定监听的变量
组件卸载时(清理):
通过useEffect
return 函数,在函数体内进行清理操作
jsx
useEffect(() => {
// 组件挂载时执行
const timer = setInterval(() => console.log('定时器运行中'), 1000);
// 返回清理函数,组件卸载时执行
return () => {
clearInterval(timer); // 清理定时器
console.log('组件卸载,清理完成');
};
}, []);
完整示例:
jsx
import { useState, useEffect } from 'react';
function LifecycleDemo() {
const [count, setCount] = useState(0);
// 1. 挂载时执行(只一次)
useEffect(() => {
console.log('组件挂载了');
return () => {
// 3. 卸载时执行
console.log('组件卸载了');
};
}, []);
// 2. 依赖 count 更新时执行
useEffect(() => {
console.log(`count 变为:${count}`);
}, [count]);
return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count + 1)}>加1</button>
</div>
);
}
8、react的路由:
React 路由用于实现单页应用(SPA)的页面跳转,核心是通过 react-router-dom
库实现:
(1)安装依赖:
bash
npm install react-router-dom
(2)基础路由示例:
jsx
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
// 1. 定义两个页面组件
function Home() {
return <h2>首页</h2>;
}
function About() {
return <h2>关于页</h2>;
}
// 2. 配置路由
function App() {
return (
<Router>
<div>
{/* 导航链接(类似a标签,但不会刷新页面) */}
<nav>
<Link to="/" style={{ marginRight: 10 }}>首页</Link>
<Link to="/about">关于</Link>
</nav>
{/* 路由匹配区域:url对应哪个组件就显示哪个 */}
<Routes>
<Route path="/" element={<Home />} /> {/* 根路径显示Home */}
<Route path="/about" element={<About />} /> {/* /about显示About */}
</Routes>
</div>
</Router>
);
}
export default App;
说明:
<Router>
:路由容器,必须包裹整个路由系统(通常放在根组件)。<Link>
:导航链接,类似 HTML 的<a>
标签,但点击时不会刷新页面,只是修改 URL;to
属性:指定跳转的路径(如to="/about"
)。<Routes>
:路由匹配容器,内部包含多个<Route>
。<Route>
:定义路径与组件的对应关系;path
:URL 路径(如path="/about"
);element
:该路径对应的组件(如element={<About />}
)。