news 2026/4/25 3:20:23

React18极客园

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
React18极客园

react18+极客园项目:https://www.bilibili.com/video/BV1ZB4y1Z7o8/?vd_source=033e18a7971697a5b8192da1e492326e
文档:https://www.yuque.com/fechaichai/qeamqf/xbai87#1ba02eb3
文档:https://www.yuque.com/fechaichai/tzzlh1
代码:https://gitee.com/libudding/chaichai1_react-basic/blob/master/public/index.html

React组件基础

jsx区别

1.变量

Vue = 双大括号 {{ }}
React = 单大括号 { }
原生 = 啥括号都不能直接写

在 JSX 里,所有 JavaScript 表达式,必须用 { } 包起来。

  1. HTML 标签、文字 → 直接写
<div>我是文字</div> 原生、 react、vue都支持
  1. JS 变量、JS 对象、JS 表达式 → 必须包 { }
{ 变量 } { 1 + 1 } { 函数调用() } { { a: 1, b: 2 } } // ← 这就是对象
// 两次{} const songs = [ { id: 1, name: '痴心绝对' }, { id: 2, name: '像我这样的人' }, { id: 3, name: '南山南' } ] function App() { return ( <div className="App"> <ul> { songs.map(item => <li>{item.name}</li>) } </ul> </div> ) } export default App

2.className

  • className 可以接受字符串
  • className=“App”
  • 类名 - className - 动态类名控制
  • className={ showTitle ? ‘title’ : ‘’}

3.style

  • Vue、原生:style=“color:red” ✅ 字符串可以
  • style 必须接受一个对象,不支持字符串
    React:style=“color:red” ❌ 直接报错
    React 只认:style={{ color: ‘red’ }}

jsx注意事项

JSX必须有一个根节点,如果没有根节点,可以使用<></>(幽灵节点)替代

JSX支持多行(换行),如果需要换行,需使用() 包裹,防止bug出现
情况 A:一行写完 → 不需要 ()

return <div>一行</div>

情况 B:多行换行 → 推荐必须加 ()

return ( <div> <p>多行</p> </div> )

因为 JS 有一个机制:自动在行尾加分号 ;

JSX可以不驼峰命名吗?绝对不行!必须驼峰!因为 JSX 本质是 JS,不是 HTML。在 JS 里,属性名不能有横杠 -,会被当成减法。

import React from 'react' import ReactDOM from 'react-dom' import './index.css' // 引入根组件App import App from './App' // 通过调用ReactDOM的render方法渲染App根组件到id为root的dom节点上 ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ) function App() { return ( <div> <div>this is a div</div> </div> ) } export default App

函数组件

  1. 组件的名称必须首字母大写
  2. 使用函数名称作为组件标签名称

类组件

  1. 类名称也必须以大写字母开头
  2. 类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性
  3. 类组件必须提供 render 方法render 方法必须有返回值,表示该组件的 UI 结构

组件状态

class Counter extends React.Component { // 定义数据 state = { count: 0 } // 定义修改数据的方法 setCount = () => { this.setState({ count: this.state.count + 1 }) } // 使用数据 并绑定事件 render () { return <button onClick={this.setCount}>{this.state.count}</button> } }
class HelloFnClass extends React.Component { state = { count: 0, list: [1, 2, 3], person: { name: 'jack', age: 18 } } changeCount = () => { this.setState({ count: this.state.count + 1, list: [...this.state.list, 4], person: { ...this.state.person, name: 'rose' } }, () => { console.log('最新值:', this.state) }) console.log('不是最新值:this.state) } render () { return <div onClick={this.changeCount}>计数器:{this.state.count}</div> } } function App () { const name = true return ( <div> <HelloFnClass></HelloFnClass> </div> ) } export default App

函数组件 + useState + useEffect简单举例

useState 永远返回数组,不管是 CDN 还是脚手架。

import { useState } from 'react' function App() { // 定义状态:count 变量,setCount 修改它的方法 const [count, setCount] = useState(0) return ( <div> <p>点击了 {count} 次</p> <button onClick={() => setCount(count + 1)}>+1</button> </div> ) } export default App
import { useState, useEffect } from 'react' function App() { const [count, setCount] = useState(0) // 一进页面就执行(像 mounted) useEffect(() => { console.log('组件加载完成啦') }, []) // ↑ 空数组 = 只执行一次 // count 变了就执行(像 watch)加载执行一次 + 变化再执行 useEffect(() => { console.log('count 变成了:', count) }, [count]) return ( <div> <p>{count}</p> <button onClick={() => setCount(count + 1)}>+1</button> </div> ) } export default App 啥都不写 → 每次渲染都执行 组件加载完成啦 ← 页面刚进来 count 变成了:0 ← 页面刚进来 count 变成了:1 ← 点第1下 count 变成了:2 ← 点第2下 count 变成了:3 ← 点第3下

为什么 React 里推荐写成箭头函数

  • 类组件必用,防止 this 丢失
  • 函数组件里根本没有 this,所以根本不存在 “this 丢失” 这一说。

普通函数在严格模式下,this 就是 undefined
React 内部默认跑在 严格模式 ‘use strict’ 下。
在严格模式里:普通函数独立运行时,this = undefined

function App() { console.log(this) // undefined } App()

因为类组件是 class 实例化 调用的:

const app = new App() app.render() // 这里 this 指向 app 实例

所以类组件才有 this,函数组件没有。

函数组件的事件绑定-传递参数

  1. onClick 必须放一个函数!
  2. onClick={ fn } 正确 → 给的是函数
  3. onClick={ fn() } 错误 → 给的是函数执行结果
  4. 想传参 → 必须套箭头函数:onClick={() => fn(参数)}
  5. vue支持直接传递<button @click=“onDel(id)”>删除
onClick={ onDel } -> onClick={ () => onDel(id) } 注意: 一定不要在模板中写出函数调用的代码 onClick = { onDel(id) } <button onClick={(e) => onDel(e, item.id)}>x</button> 如果啥都不传 直接在onDel函数中也能打印到e

组件状态useState

你完全可以在函数组件里写普通变量

function App() { // 这是一个普通变量 let count = 0 const add = () => { count = count + 1 console.log(count) // 这里确实会变! } return ( <div> <p>{count}</p> <button onClick={add}>+1</button> </div> ) }

console 会输出 1、2、3…
但页面上的数字永远不动!

因为:
React 不知道你改了数据!
React 只有在这几种情况才会重新刷新页面:

  1. state 变化(useState 里的东西)
  2. props 变化
  3. 父组件刷新

你改的是一个普通 let 变量React 根本不监听它它变了 React 也不知道,所以页面不更新。

那 useState 到底干了啥?
它干了两件事:

  1. 帮你把数据存起来(不会随着渲染丢失)
  2. 数据一改,自动触发页面重新渲染
    函数组件每次渲染,都会把里面的变量全部重新执行一遍!
    普通变量会被 “重置”,useState 会帮你把值 “记住”。
function App() { // 每次渲染都会重新执行这行! let count = 0 const add = () => { count = count + 1 console.log(count) } return ( <div> <button onClick={add}>+1</button> </div> ) }

你点击按钮 → 组件会重新渲染一次 一渲染 → 又跑了一遍:let count = 0
结果:
你刚把 count 改成 1
一渲染,又被重置成 0
永远存不住!
这就是:
普通变量会随着渲染丢失,记不住上一次的值!

const [count, setCount] = useState(0)

useState 会:
第一次渲染:初始化 count = 0
后面每次渲染:
不再执行 useState (0) 重新初始化
直接把上一次的值拿出来给你
你改了之后,它帮你存在 React 内部
下次渲染还能拿到
点击 → count 变成 1
重新渲染 → count 还是 1
再点 → 变成 2
永远不会丢!

普通变量:每次刷新都重置 → 记不住
useState:存在 React 肚子里 → 能记住
这就是:
帮你把数据存起来,不会随着渲染丢失

函数组件每更新一次,整个函数都会重新跑一遍!
普通变量会被重新创建,useState 会从 React 内部读取上一次的值,不会重置。

React hook

React Hook = 给函数组件用的 “功能工具函数”
名字都以 use 开头。

  1. 它是干嘛的?
    在 Hook 出现之前,函数组件很弱:
    不能存状态
    不能发请求
    不能做生命周期
    Hook 就是用来补全这些功能的,让函数组件也能:
    存数据(useState)
    做副作用 / 请求(useEffect)
    拿 props/context(useContext)
    缓存逻辑(useMemo/useCallback)
  2. 哪些是 Hook?
    useState
    useEffect
    useContext
    useRef
    useMemo
    useCallback
    useReducer
    自定义Hook(以 use 开头的函数)

state

不要直接修改state中的值,必须通过setState方法进行修改

class Counter extends React.Component { // 定义数据 state = { count: 0 } // 定义修改数据的方法 setCount = () => { this.setState({ count: this.state.count + 1 }) } // 使用数据 并绑定事件 render () { return <button onClick={this.setCount}>{this.state.count}</button> } }

受控组件(类、函数)

使用hook的写法写受控组件

import React, { useState } from 'react' function Demo() { const [msg, setMsg] = useState('') return ( <div> <input type="text" value={msg} onChange={(e) => setMsg(e.target.value)} /> </div> ) }

使用类的写法写受控组件

class HelloFnClassInput extends React.Component { state = { msg: '' } changeCount = (e) => { this.setState({ msg: e.target.value }) } render () { return ( <div> <div>{this.state.msg}</div> <input value={this.state.msg} onChange={this.changeCount} /> </div> ) } } function App () { return ( <div> <HelloFnClassInput /> </div> ) } export default App

非受控组件-类组件createRef + ref 属性获取 DOM

非受控组件就是通过手动操作dom的方式获取文本框的值,文本框的状态不受react组件的state中的状态控制,直接通过原生dom获取输入框的值

import React, { Component, createRef } from 'react' class Demo extends Component { // 2. 创建 ref 对象,挂载到实例上 msgRef = createRef() handleGet = () => { // 4. 通过 current 拿 DOM 元素 console.log(this.msgRef.current.value) } render() { return ( <div> {/* 3. 把 ref 绑到 input 上 */} {/* <div>{this.msgRef.current ? this.msgRef.current.value : ''}</div>不会实时同步,只有state才行 */} <input type="text" ref={this.msgRef} onChange={this.handleGet}/> <button onClick={this.handleGet}>获取值</button> </div> ) } } export default Demo createRef() 创建一个容器 ref={xxx} 把 DOM 放进这个容器 容器里的 .current 就是真实 DOM 元素 .value 就是输入框的值

非受控组件-函数组件 Hooks 写法(useRef)

import React, { useRef } from 'react' // 1. 导入 useRef 钩子 function Demo() { // 2. 调用 useRef 创建 ref 对象,和 createRef 用法几乎一样 const msgRef = useRef(null) const handleGet = () => { // 4. 同样通过 .current 拿到 DOM 和值 console.log(msgRef.current.value) } return ( <div> {/* 3. 给 input 绑定 ref,和类组件写法完全一样 */} <input type="text" ref={msgRef} /> <button onClick={handleGet}>获取值</button> </div> ) } export default Demo

React组件通信

  1. 父子关系 - props
  2. 兄弟关系 - 自定义事件模式产生技术方法 eventBus / 通过共同的父组件通信
  3. 其它关系 - mobx / redux / zustand

父传子

子组件中通过 props 接收父组件中传过来的数据
a. 类组件使用this.props获取props对象
b. 函数式组件直接通过参数获取props对象

import React from 'react' // 函数式子组件 function FSon(props) { console.log(props) return ( <div> 子组件1 {props.msg} </div> ) } // 类子组件 class CSon extends React.Component { render() { return ( <div> 子组件2 {this.props.msg} </div> ) } } // 父组件 class App extends React.Component { state = { message: 'this is message' } render() { return ( <div> <div>父组件</div> <FSon msg={this.state.message} /> <CSon msg={this.state.message} /> </div> ) } } export default App

直接给普通标签加 msg={xxx} 是不行的,这是 React 组件和原生 HTML 标签的核心区别。
传自定义数据的 1种正确写法

<div>子传父

父组件给子组件传递回调函数,子组件调用

import './app.css' import React from 'react' function Fson (props) { return ( {/* 注意调用的时候不能直接传递值,要写一个函数 */} <div onClick={() => props.changeMessage('测试2')}> {props.msg} </div> ) } class Cson extends React.Component { render () { return ( {/* 注意调用的时候不能直接传递值,要写一个函数 */} <div onClick={() => this.props.changeMessage('测试1')}> {this.props.msg} </div> ) } } class App extends React.Component { state = { message: 'this is message' } changeMessage = (newMsg) => { this.setState({ message: newMsg }) } render () { return ( <div> {/* 注意传递时候不要用函数接传递值,直接传过去 */} <Fson msg={this.state.message} changeMessage={this.changeMessage}></Fson> <Cson msg={this.state.message} changeMessage={this.changeMessage}></Cson> </div> ) } } export default App

兄弟组件通信

通过状态提升机制,利用共同的父组件实现兄弟通信
以上两种

跨组件通信Context

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法

1- 创建Context对象 导出 Provider 和 Consumer对象

const { Provider, Consumer } = createContext()

2- 使用Provider包裹上层组件提供数据

<Provider value={this.state.message}> {/* 根组件 */} </Provider>

3- 需要用到数据的组件使用Consumer包裹获取数据

<Consumer > {value => /* 基于 context 值进行渲染*/} </Consumer>
import './app.css' import React, { createContext } from 'react' const { Provider, Consumer } = createContext() function Fson () { return ( <div> <div>zi</div> <Cson></Cson> </div> ) } class Cson extends React.Component { render () { return ( <Consumer> {value => ( <div> <div>sun</div> <div>{value}</div> </div> )} </Consumer> ) } } class App extends React.Component { state = { message: 'this is message' } render () { return ( <Provider value={this.state.message}> <div> <div>fu</div> <Fson></Fson> </div> </Provider> ) } } export default App

React组件进阶

children属性

children 就是组件标签中间的内容
组件里用 props.children 接收并显示

<MyComponent> 我是中间的内容 👈 这个就是 children </MyComponent> function MyComponent(props) { return <div>{props.children}</div> }

props校验

props 校验,写在【子组件】身上!
子组件:我规定别人传什么给我
父组件:我按规定传给子组件

  1. 安装属性校验包:yarn add prop-types
  2. 导入prop-types 包
  3. 使用 组件名.propTypes = {} 给组件添加校验规则
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 3:20:19

AI Agent开发者薪资天花板:年薪百万是什么水平

你要做的就是能成为那个能干活的人。“钱景”是肯定有的&#xff0c;重点是怎么拿到offer。现在这行正处于爆发期&#xff0c;月薪3-4w很常见&#xff0c;搞得好年薪80万往上都有可能&#xff0c;大量高薪酬待遇岗都在招&#xff0c;我们这种中小厂都能给到40w税后。不用太纠结…

作者头像 李华
网站建设 2026/4/25 3:14:02

告别手动测试:如何用CANoe的LIN一致性测试模块自动化你的ECU验证流程?

从零构建LIN总线自动化测试体系&#xff1a;基于CANoe的工程实践全景指南 在汽车电子系统开发中&#xff0c;LIN总线作为CAN网络的补充&#xff0c;广泛应用于车门模块、座椅控制、空调系统等对实时性要求不高的场景。随着汽车电子架构日益复杂&#xff0c;传统手动测试方法已无…

作者头像 李华
网站建设 2026/4/25 3:11:08

使用RISC-V IDE MRS2工程调试

MounRiver Studio Ⅱ(MRS2)内置调试模块&#xff0c;支持RISC-V/ARM内核芯片工程的在线仿真调试。以下简单介绍MRS2工程调试相关操作。【调试配置页面】可以通过主菜单项“调试->调试配置”或资源区右键菜单项“调试配置”打开MRS2调试配置页面&#xff1a;【切换硬件调试器…

作者头像 李华
网站建设 2026/4/25 3:10:45

2026企业选型指南:10款主流协同办公网盘深度测评(附横向对比)

进入2026年&#xff0c;很多企业在发展过程中仍会遇到同一个核心瓶颈&#xff1a;文件体量急速膨胀&#xff0c;跨区域协作常态化&#xff0c;传统的本地存储、U盘流转和简单的邮件沟通已经无法支撑日常的高效运转。这时&#xff0c;企业就需要引入更为专业的“协同办公企业网盘…

作者头像 李华
网站建设 2026/4/25 3:09:44

04-09-09 《关键对话》博客系列

04-09-09 《关键对话》博客系列 系列说明 本系列基于 Kerry Patterson 等人的经典著作《Crucial Conversations》(关键对话)&#xff0c;将高风险沟通的核心技巧转化为8篇实用博客文章。无论你是需要处理技术分歧的工程师、需要跨团队协作的Tech Lead&#xff0c;还是任何需要…

作者头像 李华