React
基本
npm create vite
yarn create vite
js
// index.js
import { createRoot } from 'react-dom/client'
import App from './App'
const root = createRoot(document.getElementById('root'))
root.render(<App />)
jsx
// App.jsx
import React, { Component } from 'react'
const arr = ['tom','bob','jack']
const msg = 'Hello world'
const style = {backgroundColor:'skyblue'}
export default class App extends Component {
render() {
return (
<>
<div>{msg}</div>
{/* 注释 */}
<hr />
<label htmlFor="username">用户名:</label>
<input type="text" id='username' />
<hr />
<div className="box">盒子</div>
<hr />
<div style={style}>样式1</div>
<div style={{backgroundColor:null ? 'skyblue' : 'pink'}}>样式2</div>
<ul>
{arr.map((item,index)=>
<li key={index}>{item}</li>
)}
</ul>
</>
)
}
}
响应
jsx
import React, { Component } from 'react'
import './app.css'
export default class App2 extends Component {
state = {
num1: 1,
num2: 1,
}
render() {
return (
<>
<div className="pink">
<h2>数字为:{this.state.num1}</h2>
<button
onClick={() =>
this.setState({ num1: this.state.num1 + 1 })
}
>
累加1
</button>
<button onClick={this.addNum.bind(this)}>累加2</button>
<button onClick={() => this.addNum()}>累加3</button>
<button onClick={this.addNum2}>测试</button>
</div>
<div className="skyblue">
<h2>数字为:{this.state.num2}</h2>
<button onClick={this.setNum.bind(this, 2)}>设为2</button>
<button onClick={() => this.setNum(3)}>设为3</button>
</div>
</>
)
}
addNum() {
this.setState({ num1: this.state.num1 + 1 })
// 构造函数中的this才指向实例对象
}
setNum(n) {
this.setState({ num2: n })
// 函数中的this并非实例对象
// 可以改成箭头函数
}
addNum2 = () => {
console.log(this)
this.setState({ num1: this.state.num1 + 1 })
}
}
jsx
//函数组件没有this, 故使用生命周期钩子
import { useState } from 'react'
export default function App3() {
const [num, setNum] = useState(0)
const add = () => setNum(num + 1)
const set = n => setNum(n)
return (
<div>
<h2>数字为:{num}</h2>
<button onClick={add}>累加</button>
<button onClick={() => set(0)}>归零</button>
</div>
)
}
Hooks
jsx
import { useState, useEffect } from 'react'
import './app.css'
//函数组件没有this, 故使用生命周期钩子
export default function App3() {
const [num1, setNum1] = useState(0)
const [num2, setNum2] = useState(0)
const [num3, setNum3] = useState(0)
useEffect(() => {
console.log('不检测更新')
}, [])
useEffect(() => {
console.log('检测所有更新')
})
useEffect(() => {
console.log('检测num1更新')
}, [num1])
useEffect(() => {
console.log('检测num1、num2更新')
}, [num1, num2])
useEffect(() => {
return () => {
console.log('组件销毁')
}
})
return (
<>
<div className="skyblue">
<h2>num1:{num1}</h2>
<button onClick={() => setNum1(num1 + 1)}>add1</button>
</div>
<div className="pink">
<h2>num2:{num2}</h2>
<button onClick={() => setNum2(num2 + 1)}>add2</button>
</div>
<div className="skyblue">
<h2>num3:{num3}</h2>
<button onClick={() => setNum3(num3 + 1)}>add3</button>
</div>
</>
)
}
jsx
import { useState, memo, useCallback, useMemo } from 'react'
export default function App7() {
const [num, setNum] = useState(1)
// 组件更新的时候把定义的函数和变量都重新定义了一遍
// 因此这两个东西就是为了不让那些东西重新定义
const func1 = useCallback(() => setNum(num => num + 1), [])
const func2 = useMemo(() => () => setNum(num => num + 1), [])
return (
<div>
<h3>数字{num}</h3>
<Child2 func1={func1} func2={func2} />
<hr />
<Child1 />
</div>
)
}
const Child1 = memo(() => {
console.log('不然每次更新都会打印')
return <>子组件 </>
})
const Child2 = memo(props => {
console.log('不然每次更新都会打印')
return (
<>
<button onClick={() => props.func1()}>累加</button>
<button onClick={() => props.func2()}>累加</button>
</>
)
})
组件通信
jsx
import { useState } from 'react'
export default function App4() {
const [num, setNum] = useState(1)
return <Father num={num} setNum={setNum} />
}
function Father(props) {
return <Child num={props.num} setNum={props.setNum} />
}
function Child(props) {
return (
<>
<h2>子组件 - {props.num}</h2>
<button onClick={() => props.setNum(0)}>归零</button>
</>
)
}
jsx
import { useState, createContext, useContext } from 'react'
const numCtx = createContext()
export default function App5() {
const [num, setNum] = useState(1)
return (
// 提供
<numCtx.Provider value={{ num, setNum }}>
<Father />
</numCtx.Provider>
)
}
const Father = () => <Child />
function Child() {
// 接收
const { num, setNum } = useContext(numCtx)
return (
<>
<h2>子组件 - {num}</h2>
<button onClick={() => setNum(0)}>归零</button>
</>
)
}
表单取值
jsx
import { useState, useRef } from 'react'
export default function App6() {
const [value, setValue] = useState('input')
const ele = useRef(null)
return (
<div>
<h2>受控组件</h2>
<input
type="text"
value={value}
onChange={e => setValue(e.target.value)}
/>
<div>{value}</div>
<hr />
<h2>非受控组件</h2>
<input type="text" ref={ele} />
<button onClick={() => console.log(ele.current.value)}>
获取dom值
</button>
</div>
)
}
Mobx 状态管理
npm install --save mobx
js
import { makeAutoObservable, runInAction } from 'mobx'
class Number {
num = 0
constructor() {
makeAutoObservable(this)
}
add = () => (this.num += 1)
reset = () => (this.num = 0)
plus = async () => {
const times = await new Promise(r => setTimeout(() => r(2), 1000))
runInAction(() => (this.num *= times))
}
}
export default new Number()
jsx
import React from 'react'
import number from './state'
import { observer } from 'mobx-react-lite'
export default observer(() => (
<>
<h2>状态管理</h2>
<h3>{number.num}</h3>
<button onClick={number.add}>累加</button>
<button onClick={number.reset}>归零</button>
<button onClick={number.plus}>二倍</button>
</>
))
Router
yarn add react-router-dom
基本用法
jsx
import {
createBrowserRouter,
createHashRouter,
} from 'react-router-dom'
export default createBrowserRouter([
{
path: '/',
element: <div>home</div>,
},
{
path: '/login',
element: <div>login</div>,
},
{
path: '/about',
element: <div>about</div>,
},
])
jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import router from './router'
import { RouterProvider,Link } from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<h1>React Router</h1>
<Link to='/login'>登录</Link>
<RouterProvider router={router} />
</React.StrictMode>
)
编程导航
jsx
import { useNavigate } from 'react-router-dom'
export default function Login() {
const navigate = useNavigate()
// 替换跳转 无记录
const goAbout1 = () => navigate('/about',{replace:true})
// SearchParam 传参
const goAbout2 = () => navigate('/about?id=1001')
// Params 传参 需要路由 '/about/:id'
const goAbout3 = () => navigate('/about/1001')
return (
<>
<div>Login</div>
<button onClick={() => navigate('/about')}>goAbout</button>
</>
)
}
jsx
import { useSearchParams, useParams } from 'react-router-dom'
const About = () => {
const [params] = useSearchParams()
console.log(params)
const id1 = params.get('id')
const {id} = useParams()
return <div>this is about {id1 ?? id}</div>
}
export default About
嵌套路由
jsx
{
path: '/',
element: <Layout />,
children: [
{
index: true,
element: <div>二级默认渲染</div>,
},
{
path: 'article',
element: <div>文章</div>,
},
],
}
jsx
import { Outlet, Link } from 'react-router-dom'
export default function Layout() {
return (
<div>
<Link to="/">默认</Link>
<Link to="/article">文章</Link>
<div>二级路由出口位置</div>
<Outlet />
</div>
)
}
404页面
js
{
path:'*',
element: <div>404 Not Found </div>
}