react 18 基础教程
1.React开发环境搭建
执行 npx create-react-app 项目名称 命令来创建项目
2.实现列表渲染
在react中可以通过在{}中写入js表达式来执行js代码,所以可以通过如下手段来执行来实现列表的渲染。
function App() {
let list = [
{id:1,name:"Vue"},
{id:2,name:"React"},
{id:3,name:"Angular"}
]
return (
<div className="App">
{list.map((item)=>{
return <p key={item.id}>{item.name}</p>
})}
</div>
);
}
3.实现基础条件渲染
在react中可以通过逻辑与“&&”或者三元运算符来实现基础的条件渲染
function App() {
let isLogin = false
return (
<div className="App">
{isLogin && <span>用户已登录</span>}
{isLogin ? <span>用户已登录</span> : <span>用户未登录</span>}
</div>
);
}
4.实现复杂的条件渲染
复杂的条件渲染可以通过定义函数在函数中进行
function App() {
let isLogin = 2
const getLoginState = () => {
if (isLogin === 0) {
return <span>用户未登录</span>
} else if (isLogin === 1) {
return <span>用户已登录</span>
} else {
return <span>用户登录失效</span>
}
}
return (
<div className="App">
{getLoginState()}
</div>
);
}
5.react中事件的绑定
在react中可以通过onClick来绑定点击事件如下:
function App() {
const handleClick = ()=>{
console.log("点击我")
}
return (
<div className="App">
<button onClick={handleClick}>点击我</button>
</div>
);
}
如果需要使用事件对象参数,则需要在函数中添加参数e
function App() {
const handleClick = (e)=>{
console.log("事件对象参数",e)
}
return (
<div className="App">
<button onClick={handleClick}>点击我</button>
</div>
);
}
如果要使用自定义参数则需要进行如下修改
function App() {
const handleClick = (val) => {
console.log("自定义参数",val)
}
return (
<div className="App">
<button onClick={()=>{handleClick("hello")}}>点击我</button>
</div>
);
}
下面则是既需要事件对象参数,又需要自定义参数的例子
function App() {
const handleClick = (val,e) => {
console.log("自定义参数",val)
console.log("事件对象参数",e)
}
return (
<div className="App">
<button onClick={(e)=>{handleClick("hello",e)}}>点击我</button>
</div>
);
}
5.react中基础组件的使用
通过使用函数来定义组件,但是注意作为组件的函数必须要开头大写
function App() {
const Button = ()=>{
return <botton>基础按钮</botton>
}
return (
<div className="App">
<Button></Button>
</div>
);
}
6.useState的使用
useState是一个React Hook,它允许我们向组件添加一个状态变量,从而控制影响组建的渲染结果,使用方法如下
import {useState} from 'react'
function App() {
let [num,setNum] = useState(1)
let [person,setPerson] = useState({
name:"小花",
age:20
})
// num++
const handleAdd = ()=>{
setNum(num+1)
}
// 修改person
const updatePerson = ()=>{
setPerson({
...person,
name:"KK"
})
}
return (
<div className="App">
<span>{num}</span>
<span>{person.name}</span>
<button onClick={()=>handleAdd()}>num+1</button>
<button onClick={()=>updatePerson()}>修改用户名</button>
</div>
);
}
7.基础样式的控制
react的基础样式控制有两种方法,行类样式和class类名控制,分别如下
行类样式(不推荐)
<div style={{ color: 'red' }}>测试内容</div>
class类名控制
.foo {
color: red;
}
<div className='foo'>测试内容</div>
8.组件通信
父传子,在父组件中绑定数据,在子组件中的props中接收数据
// 父传子
function Son(props) {
console.log(props)
return <div>this is Son</div>
}
function App() {
let name = "app name"
return (
<div className="App">
<Son name = {name}></Son>
</div>
);
}
子组件中嵌入的标签可以通过props中的children属性获取
function Son(props) {
console.log(props)
console.log(props.children)
return <div>this is Son</div>
}
function App() {
let name = "app name"
return (
<div className="App">
<Son name = {name}>
<span>this is span</span>
</Son>
</div>
);
}
子传父,在组件中调用父组件中的函数并传递参数
// 子传父
function Son(props) {
let name = "this is son"
return <div>
<button onClick={()=>{props.onGetMsg(name)}}>获取数据</button>
</div>
}
function App() {
const getMsg = (msg)=>{
console.log(msg)
}
return (
<div className="App">
<Son onGetMsg = {getMsg}></Son>
</div>
);
}
兄弟间的组件通信,可以通过子传父,然后再由父传子来实现
使用context机制跨层传递数据
import './App.css';
// 1.createContext方法创建一个上下文对象
import { createContext, useContext } from 'react'
const MsgContext = createContext();
// 2.在顶层组件通过Provider组件提供数据
// 3.在底层组件通过useContent钩子函数使用数据
function A(props) {
return <div>
this is A
<B></B>
</div>
}
function B(props) {
const msg = useContext(MsgContext)
return <div>
this is B
{msg}
</div>
}
function App() {
let msg = "app msg"
return (
<div className="App">
<MsgContext.Provider value={msg}>
<A></A>
</MsgContext.Provider>
</div>
);
}
export default App;
9.useEffect依赖项参数说明
useEffect是React中的一个钩子函数,用于处理副作用操作。副作用是指在组件渲染过程中,可能会对外部环境产生影响的操作,比如数据获取、订阅事件、操作DOM等。
useEffect副作用函数的执行时机存在多种情况,根据传入依赖项的不同,会有不同的执行表现,
没有依赖项:组件初始渲染+组件更新时执行
空数组依赖:只在初始渲染时执行一次
添加特定依赖项:组件初始渲染+特点依赖项变化时执行
useEffect清除副作用,比如在useEffect中开启了一个定时器,我们想在组件卸载时把这个定时器再清理掉,这个过程就是清理副作用,例子如下
useEffect(()=>{
let timer = setInterval(()=>{
console.log("定时器执行中......")
},1000)
return ()=>{
// 清除副作用(组件卸载时)
clearInterval(timer)
}
})
10.自定义hook的实现
使用use...前缀命名自定义hooks。
自定义hooks应该使用use关键字作为前缀。
自定义hooks应该在函数组件或自定义hooks中调用其他hooks。
确保自定义hooks内部的状态更新正确,避免陷阱如悬挂的状态。
例子如下:
function useToggle() {
const [value, setValue] = useState(true)
const toggle = () => setValue(!value)
return {
value,
toggle
}
}
function App() {
const { value, toggle } = useToggle()
return (
<div className="App">
</div>
);
}
11.Redux教程
Redux是一种状态管理工具,类似于vue3的Pinia。官网推荐使用Redux Toolkit工具来应用Redux,通过命令npm install @reduxjs/toolkit react-redux安装相关依赖。接下来相关步骤如下:
1.代码分层
2.提供reducer模块
import { createSlice } from '@reduxjs/toolkit'
const counter = createSlice({
//命名空间,name的值会作为action type前缀
name: "counter",
initialState: {
count: 0,
list: []
},
// 1/定义reducer更新状态函数 2、组件中dispatch使用的action
// 内置了状态不可变的插件
reducers: {
// 同步
add(state, action) {
console.log(state, action);
state.count++
},
sub(state) {
state.count--
},
pus(state, action) {
state.list.push(Math.floor(Math.random() * 1000))
},
del(state, action) {
state.list.splice(action.payload, 1)
}
}
})
// 淡出action函数
export const { add, sub, pus, del } = counter.actions
// 定义一个异步action
export const subAsync = (payload) => {
return async (dispatch, getState) => {
setTimeout(() => {
dispatch(sub())
}, 3000)
}
}
// 导出reducer生成store
export default counter.reducer
3.创建store
// 创建store
import { configureStore } from '@reduxjs/toolkit'
import counter from './modules/counter'
export const store = configureStore({
reducer: {
counter
}
})
4.在入口集成Redux
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// 引入store和Provider
import { store } from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
reportWebVitals();
5.在组件中获取状态和更新状态
import './App.css';
import { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { add, subAsync, pus, del } from './store/modules/counter'
function App() {
const dispatch = useDispatch()
const { count, list } = useSelector(state => state.counter)
return (
<div>
<ul>
<li>{count}</li>
<li onClick={() => {
dispatch(add())
}}>
<button>add</button>
</li>
<button onClick={() => {
dispatch(subAsync())
}}>-1</button>
</ul>
<hr />
<ul>
{
list.map((item, index) =>
<li key={index} onClick={() => {
dispatch(del(index))
}}>{item}</li>
)
}
<button onClick={() => { dispatch(pus()) }}>添加</button>
</ul>
</div>
);
}
export default App;
12.ReactRouter教程
1.搭建路由
执行命令npm i react-router-dom安装路由相关依赖,接下来在src文件夹下创建router文件并在其内创建路由文件index.js如下图所示:
接下来在路由文件中进行路由配置
import Login from "../pages/Login";
import App from "../App";
import { createBrowserRouter } from "react-router-dom";
const router = createBrowserRouter([
{
path:'/login',
element:<Login/>
},
{
path:'/index',
element:<App/>
}
])
export default router
在这之后,在项目的入口文件中引入RouterProvider和router并进行配置,这样基本的路由配置就完成了
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import reportWebVitals from './reportWebVitals';
import { RouterProvider } from "react-router-dom";
import router from './router';
// 引入store和Provider
import { store } from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<RouterProvider router={router}></RouterProvider>
</Provider>
);
reportWebVitals();
2.路由的跳转
路由的跳转分为两种写法,一个是声明式的写法,用Link标签。一个是命令式的写法用useNavigate
import './index.css';
import { Link,useNavigate } from 'react-router-dom';
function Login() {
const navigate = useNavigate()
return (
<div>
我是登录页
<Link to="/index">跳转首页</Link>
<button onClick={()=>{navigate("/index")}}>跳转首页</button>
</div>
);
}
export default Login;
3.路由跳转传参
路由跳转传参也分为两种
searchParams传参
<button onClick={()=>{navigate("/index?id=100&name=Tom")}}>跳转首页</button>
import { useSearchParams } from 'react-router-dom';
import './App.css';
function App() {
const [params] = useSearchParams()
console.log(params.get('id'))
console.log(params.get('name'))
return (
<div>
我是首页
</div>
);
}
export default App;
params传参
const router = createBrowserRouter([
{
path:'/login',
element:<Login/>
},
{
path:'/index/:id/:name',
element:<App/>
}
])
<button onClick={()=>{navigate("/index/100/Tom")}}>跳转首页</button>
import { useParams } from 'react-router-dom';
import './App.css';
function App() {
const params = useParams()
console.log(params)
return (
<div>
我是首页
</div>
);
}
export default App;
4.ReactRouter的嵌套路由配置
使用children属性配置路由嵌套关系,使用<Outlet>组件配置二级路由渲染位置
const router = createBrowserRouter([
{
path:'/login',
element:<Login/>
},
{
path:'/index',
element:<App/>,
children:[
{
path:"ArticleManage",
element:<ArticleManage/>
}
]
}
])
import { useParams } from 'react-router-dom';
import './App.css';
import { Outlet } from 'react-router-dom';
function App() {
const params = useParams()
console.log(params)
return (
<div>
我是首页
————————————————
<Outlet/>
</div>
);
}
export default App;
5.ReactRouter的默认二级路由配置
当访问的是一级路由时,默认的二级路由组件可以得到渲染,只需要在二级路由的位置去掉path,并设置index属性为true即可。
6.ReactRouter的404路由配置
当浏览器输入url的路径在整个路由配置中都找不到对应的path,为了用户体验,可以使用404兜底组件进行。1.准备一个404组件,2.在路由表的末尾以*号作为路由path配置路由
const router = createBrowserRouter([
{
path:'/login',
element:<Login/>
},
{
path:'/index',
element:<App/>,
children:[
{
path:"ArticleManage",
element:<ArticleManage/>
}
]
},
{
path:'*',
element:<NotFound/>
},
])
7.ReactRouter有两种路由模式,history模式和hash模式,这个和vue是一样的。分别可以通过createBrowerRouter和createHashRouter函数来进行创建