react 语法基础
-
概念介绍
-
项目初始化
-
目录结构
-
单文件组件 SFC 与 mustach语法 模板语法
-
响应式数据 useState
-
react 合成事件
-
useEffect 生命周期与监听
-
组件开发
-
基础使用
-
父传子
-
子传父
-
插槽
-
上下文 context useContext 跨层级数据共享
-
-
react 状态管理库 redux redux-toolkit(最佳实践) mobx dva ...... reducer
-
react 路由 react-router-dom
-
UI库的使用 ant design 系列 antd mobile nutUi
1.react概念介绍
11年 facebook (meta) 开源react
第一次提出的概念:
组件化开发
响应式数据 数据驱动 最小粒度更新算法 性能远超vue ref reactive
虚拟dom更新 驱动 真实dom更新 diff算法 fiber算法
react 语法 更加倾向原生JS
13年 10月 vue 发布了vue2.x ----22年
vue: 融合了 react 核心理念 和核心代码 融合和 anglur js 指令系统 14个指令
- vue3语法 模仿了react 16.8语法
react 版本历史
<16.8 版本 基于 类的开发(面向对象的开发) 学习难度非常高
>
16.8 版本 基于函数式的开发(面向函数开发) 学习难度较低 【大量的项目 都是基于函数式语法】目前最新react版本 19.x 16.x 17.x 18.x 19.x
2.项目初始化
react 组成部分:
-
react 核心语法
react
-
react 操作dom节点的库
react-dom
-
react 跨端原生开发(安卓 ios 小程序):
react native
RN
https://react.docschina.org/
-
脚手架: 可以通过某种工具 快速的创建项目 (某种工具===脚手架工具)
-
vue vite vue-cli webpack
-
react vite create-react-app
-
2.1vite初始化 项目过程命令
pnpm create vite 项目名 --template react
pnpm install
pnpm run dev
3.单文件组件 SFC
文件后缀 .js .jsx .tsx
一个函数 return 一段html 代码(被渲染到页面上 根据挂载的根节点确定渲染位置)
import './app.css'
function App() {
const xxx = 1000;
let yyy = 2000;
// mustach {表达式} <></> 有且只有一个根节点
// vue{{}} template ES6 ${}
return (
<>
<div id="app" >hello world--- {xxx}
<p className="box"> 我是xxx 你好啊</p>
</div>
<div >我是嘻嘻嘻</div>
</>
)
}
export default App;
import './app.css'
export default () => {
const a = 1100;
return (
<div className="box">
{a}
</div>
)
}
4.响应式数据 useState
数据改 页面改
页面改 数据改
const [变量,修改变量函数] = useState(初始值);
//修改变量函数: 调用函数时,
//1.首先修改变量的值
//2.通过diff算法(递归) 比对 所有的dom节点(只是比对虚拟dom),找出使用了这个变量的dom节点
//3.根据render函数,重新渲染涉及到的 真实 dom节点
import {useState} from 'react'
export const ()=>{
// 变量==响应式数据的特征
//set变量 == 接受一个 可以修改 这个变量的函数
//之后修改数据变量,必须使用 set变量的方法进行修改
const [变量,set变量] = useState(初始值);
const [a,setA] = useState(1000);
const reduce = ()=>{
//新数据如果是根据元数据改变过来的
// 不要直接修改原数据的值 a-1 a--
// 如果原值是引用数据类型,一定注意 深浅拷贝问题
// 修改引用数据类型时,应该先通过拷贝拿到原数据 给一个临时变量存起来 更改临时变量 最后setXXx修改响应式数据
setA(a-1)
}
}
import './app.css'
import { useState } from 'react';
export default () => {
const [a,setA] = useState(1000)
const reduce = ()=>{
// 异步修改函数 promise? setTimeout
// 闭包: 永远拿到的都是老值
setA(a-1)
}
// const add = ()=>{
// setA(a+1)
// }
return (
<>
<button onClick={reduce}>-</button>
<h1>{a}</h1>
<button onClick={()=>setA(a+1)}>+</button>
</>
)
}
5.react 合成事件
<div on事件类型={事件的执行函数}>
const ()=>{
const changeNum = ()=>{}
return (<div οnclick={changeNum}>)
}
const ()=>{
return (<div οnclick={()=>{}}>)
}
const ()=>{
const changeNum = (num)=>{}
return (<div οnclick={()=>changeNum(1000)}>)
}
const ()=>{
const changeNum = (event,num)=>{}
return (<div οnclick={(event)=>changeNum(event,1000)}>)
}
6.useEffect 副作用函数 hooks
useEffect 代替生命周期 (挂载完成,卸载之前)
<16.8版本 完整的生命周期(类组件为主 没有函数式组件)
useEffect 代替数据的监听(vue:watch computed)
import {useEffect} from 'react'
export default ()=>{
//副作用:watch computed 就是监听的变量
useEffect(()=>{},[副作用])
}
生命周期 :
-
初始化周期 init
-
挂载周期 mounting
-
componentWillMount 组件挂载之前
-
componentDidMount 组件挂载之后 ----mounted
-
-
更新周期 updation
-
卸载周期 unMounting
- componentWillUnmount 卸载之前 销毁之前
6.1 useEffect 代替生命周期
不去监听任何数据的改变 就代表的是 挂载完成周期
import {useEffect} from 'react'
export default ()=>{
useEffect(()=>{
//函数体:挂载完成执行的代码 componentDidMount
return ()=>{
//销毁周期的代码
}
},[])
//这里一定要写[],不然就会死循环
}
6.2 useEffect 监听某个数据的改变
注意:!!!
如果在监听某个变量的改变,useEffect 函数体中 千万不要
更改这个变量的值
的代码副作用的
[]
一定要写,不写会造成死循环
//变量1 变量2 任意1个变量的值发生改变 函数体就会自动执行一次
import {useEffect} from 'react'
export default ()=>{
useEffect(()=>{
//函数体:挂载完成执行的代码 componentDidMount
return ()=>{
//销毁周期的代码
}
},[监听的变量1,监听的变量2...])
}
//变量1 变量2 任意1个变量的值发生改变 函数题就会自动执行一次
import {useEffect,useState} from 'react'
export default ()=>{
const [a,setA] = useState(0)
useEffect(()=>{
//函数体:挂载完成执行的代码 componentDidMount
setA(a+1)
},[a])
useEffect(()=>{
//函数体:挂载完成执行的代码 componentDidMount
},[监听的变量2])
}
7.useRef 获取dom || 获取子组件的实例对象
import {useRef,useEffect} from 'react'
export default ()=>{
const boxRef = useRef(null);
useEffect(()=>{
console.log(boxRef.current) // <div ref={boxRef}> xxx </div>
},[])
return <div ref={boxRef}> xxx </div>
}
import { useEffect,useState,useRef } from 'react'
export default function App1() {
const [num,setNum] = useState(100)
const [a,setA] = useState(122)
const boxRef = useRef(null);
// const timer = setInterval(() => {
// console.log('定时器');
// },10000)
useEffect(() => {
// 挂载完成
// let ulDom = document.querySelector('ul')
// console.log(ulDom);
console.log(boxRef.current);
// 销毁周期
// return () => {
// clearInterval(timer)
// }
}, [])
const changeNum = () => {
let num1 = num + 1
setNum(num1)
console.log(num1);
}
useEffect(()=>{
console.log('变化了');
console.log(num);
console.log(a);
},[num,a])
return (
<div>
<div ref={boxRef} className="box">我是一个盒子</div>
<ul>
<li>菜单{num}</li>
<li>菜单02</li>
<li>菜单03</li>
<li>菜单04</li>
<li>菜单05</li>
</ul>
<button onClick={changeNum}>递增</button>
<button onClick={()=>setA(a+1)}>A</button>
</div>
)
}
7.判断 三目运算
三目运算 使用场景: 显示隐藏 dom节点 动态样式 display:none 动态类名
import React from 'react'
export default function App2() {
const [gedner,setGender] = useState(0)
return (
<div>
{gender%2==0?<span>男</span>:<span>女</span>}
</div>
)
}
import React,{useState} from 'react'
// 子组件
const getGender = (gender) => {
return gender%2==0?<span>男</span>:<span>女</span>
}
// 导出一个默认的函数组件App2
export default function App2() {
// 使用useState钩子,初始化gender为0,并设置setGender函数用于更新gender的值
const [gedner,setGender] = useState(0)
return (
<div>
{getGender(gedner)}
<button onClick={()=>setGender(gedner+1)}>++++</button>
</div>
)
}
- 判断成绩 >90 输出优秀,否则什么都不输出
import React,{useState} from 'react'
export default function App3() {
const [num,setNum] = useState(85)
return (
<div>
{num>=90?<h1>优秀</h1>:null }
</div>
)
}
成绩范围
90 优秀
80 良好
70 中等
60 及格
60以下 不及格
import React,{useState} from 'react'
const getGreade = (num)=>{
let str = '不及格'
switch(Math.floor(num/10)){
case 10:
case 9:str = '优秀'; break;
case 8: str = '良好';break;
case 7:str = '中等'; break;
case 6: str = '及格';break;
default:str = '不及格';
}
return <h1>{str}</h1>
}
export default function App4() {
const [num,setNum] = useState(46)
return (
<>
{getGreade(num)}
{/* {
num>=90?<h1>优秀</h1>: num>=80?<h1>良好</h1>:num>=70?<h1>中等</h1>:num>=60?<h1>及格</h1>:<h1>不及格</h1>
} */}
</>
)
}
- 动态样式操作
import React ,{useState} from 'react'
export default function App5() {
const [gender,setGender] = useState(0)
return (
<div>
{/* 动态样式 */}
<h1 style={{display:gender%2==0?'block':'none',background:'red' } }>男</h1>
<h1 style={{display:gender%2==1?'block':'none',background:'red' } }>女</h1>
<button onClick={()=>setGender(gender+1)}>+++</button>
</div>
)
}
- 动态类名
开关灯效果
import React, { useState } from 'react'
import './App.css'
export default function App6() {
const [isLigiht, setIsLight] = useState(true)
return (
<>
<div className={isLigiht?'box active':'box black'}>
</div>
<button onClick={() => setIsLight(true)}>开灯</button>
<button onClick={() => setIsLight(false)}>关灯</button>
</>
)
}
- 选项卡 tab实现 17:05
希望清单的 标题
希望列表
添加希望
点击某个标题: 选中当前这个标题(添加选中样式) , 显示对应的内容区域
8.循环 map
循环数组 ||对象
最终目的: 必须要有 return 出来的 html代码到 页面上
import React,{useState } from 'react'
export default function App8() {
const [userList,setUserList] = useState([
{name:'张麻子',age:40},
{name:'黄四郎',age:35},
{name:'马邦德',age:42},
])
const add = ()=>{
const obj = {name:'胡桂源',age:20}
// const list = [...userList]
// list.push(obj)
// // setUserList(userList) //地址没有发生改变 ,所以不会重新渲染
// // 需要临时的空的数组 有新的地址 装所有的新数据,再调用修改变量的值 set方法 才可以有响应式数据的特征
// setUserList(list)
userList.push(obj)
setUserList([...userList]) //地址没有发生改变 ,所以不会重新渲染
// 需要临时的空的数组 有新的地址 装所有的新数据,再调用修改变量的值 set方法 才可以有响应式数据的特征
}
return (
<>
<button onClick={add}>添加数据</button>
{
userList.map((item,index)=>{
return <p key={index}>姓名:{item.name};年龄:{item.age}</p>
})
}
</>
)
}
const [students,setStudents] = useState([
{sno:'12000',name:'纪英龙',greade:95},
{sno:'1202200',name:'查其才',greade:85},
{sno:'123330',name:'蒋盛林',greade:55},
])
//渲染默认数据
//点击事件 添加一个对象 {sno:'222',name:'xxxx',greade:55},
// 删除按钮 删除对应的数据
9.受控组件 与 非受控组件|表单 获取数据
非受控组件 : 通过 useRef 获取到dom ,再通过dom节点获取表单数据 antd
受控组件: 通过useState 做数据的绑定 加上 onChange 事件 e.target.value 然后赋值给那个变量useState=e.target.value
import React,{useRef} from 'react'
export default function App9() {
// 非受控组件 useRef
const accountRef = useRef(null);
const passwordRef = useRef(null);
const saveBtn = () => {
console.log(accountRef.current.value);
console.log(passwordRef.current.value);
}
return (
<>
账号: <input type="text" ref={accountRef} />
密码: <input type="password" ref={passwordRef}/>
<button onClick={saveBtn}>提交</button>
</>
)
}
import React,{useState} from 'react'
export default function App9() {
const [formData,setFormData] = useState({account:'',password:''})
const saveBtn = () => {
console.log(formData);
}
const change = (data)=>{
setFormData(data)
}
return (
<>
账号: <input type="text" onChange={(e)=>change({account:e.target.value, password:formData.password})}/>
密码: <input type="password" onChange={(e)=>change({account:formData.account, password:e.target.value})} />
<button onClick={saveBtn}>提交</button>
</>
)
}