以下是React18版本的基础学习资源
点击我获取更多学习资源
import logo from './logo.svg';
import './App.css';
function App() {
const imgData = {
className: 'small',
style: {
wdith: '200px',
height: '200px',
backgroundColor: 'grey'
}
}
return (
<div className="App">
<img src={logo}
alt=""
{...imgData}
/>
</div>
);
}
export default App;
import './App.css';
function Detail({content, active}) {
return (
<>
<p>{content}</p>
<p>状态:{active}</p>
</>
)
}
function Article({title, detailData}) {
return (
<div>
<h2>{title}</h2>
<Detail {...detailData}></Detail>
</div>
)
}
function App() {
const articleData = {
title: '标题111',
detailData: {
content: '内容111',
active: true
}
}
return (
<>
<Article
{...articleData}
/>
</>
);
}
export default App;
import './App.css';
function List({children}) {
return (
<ul>
{children}
</ul>
)
}
function App() {
return (
<>
<List>
<li>列表1</li>
<li>列表2</li>
</List>
</>
);
}
export default App;
import './App.css';
function List({children, title, footer = <div>默认底部</div>}) {
return (
<>
<h2>{title}</h2>
<ul>
{children}
</ul>
{footer}
</>
)
}
function App() {
return (
<>
<List
title="列表title"
footer={<p>这是底部内容</p>}
>
<li>列表1</li>
<li>列表2</li>
</List>
</>
);
}
export default App;
import './App.css';
import {useState} from 'react'
function Detail({onActive}) {
const [status, setStatus] = useState(false)
function handleClick() {
setStatus(!status)
onActive(status)
}
return (
<div>
<button onClick={handleClick}>按钮</button>
<p style={{
display: status ? 'block' : 'none'
}}>Detail内容</p>
</div>
)
}
function App() {
function handleActive (status) {
console.log(status)
}
return (
<>
<Detail onActive={handleActive}></Detail>
</>
);
}
export default App;
import './App.css';
import {useReducer, useState} from 'react'
function countReducer(state, action) {
switch(action.type) {
case 'increment':
return state + 1
case 'decrement':
return state - 1
default:
throw new Error()
}
}
function App() {
const [state, dispatch] = useReducer(countReducer, 0)
const handleIncrement = () => dispatch({type: 'increment'})
const handleDecrement = () => dispatch({type: 'decrement'})
return (
<>
<button onClick={handleIncrement}>+</button>
<span>{state}</span>
<button onClick={handleDecrement}>-</button>
</>
);
}
export default App;
import './App.css';
import { forwardRef, useImperativeHandle, useRef } from 'react'
const Child = forwardRef(function(props, ref) {
useImperativeHandle(ref, () => ({
myFun: ()=> {
console.log('子方法被调用')
}
}))
return (<div>子组件</div>)
})
function App() {
const childRef = useRef()
const handleClick = () => {
childRef.current.myFun()
}
return (
<>
<Child ref={childRef} />
<button onClick={handleClick}>调用子方法</button>
</>
);
}
export default App;
import './App.css';
import { useEffect, useState } from 'react'
function App() {
const [count, setCount] = useState(0)
const [count2, setCount2] = useState(0)
// 只要界面一变化,都会触发
useEffect(() => {
console.log('useEffect')
return () => {
// 当页面卸载执行,清理数据
}
})
// useEffcet(() => {
// return () => {
// console.log('类似于componentWillUnmount,通常用于清除副作用');
// }
// }, [])
// useEffcet(() => {
// console.log('类似于componentDidMount,通常在此处调用api获取数据')
// }, [])
// useEffect useEffect 返回的是一个清理函数,
//不能是async的promise,如果里面有异步执行,可以用以下方法
// useEffect(() => {
// console.log('useEffect')
// return () => {
// ;(async () => {
// const data = await http.get('....')
// })();
// // 当页面卸载执行,清理数据
// }
// })
//只有count才会触发
// useEffect(() => {
// console.log('useEffect')
// }, [count])
const handleClick = () => {
setCount(count + 1)
}
const handleClick2 = () => {
setCount2(count2 + 1)
}
return (
<>
<button onClick={handleClick}>点击触发{count}</button>
<button onClick={handleClick2}>点击触发2{count2}</button>
</>
);
}
export default App;
import './App.css';
import { useMemo, useState } from 'react'
function DoSomeMath ({value}) {
// 利用useMemo,可以缓存result,不会重新计算,但该函数依然会执行
console.log('DosomeMathc执行了')
const result = useMemo(() => {
console.log('DosomeMathc2执行了')
let result = 0
for (let i = 0; i < 100000; i++) {
result += value * 2
}
return result
}, [value])
return (<div>{result}</div>)
}
function DoSomeMath2 ({value}) {
// 外面变化,在value没变化的情况下,内部依然都要重新计算,不符合逻辑
console.log('DosomeMathc执行了')
let result = 0
for (let i = 0; i < 100000; i++) {
result += value * 2
}
return (<div>{result}</div>)
}
function App() {
const [inputValue, setInputValue] = useState(5)
const [count, setCount] = useState(0)
return (
<>
<p>count值为: {count}</p>
<button
onClick={() => setCount(count + 1)}>
点击更新
</button>
<br/>
<input type="number"
value={inputValue}
onChange={(e) => setInputValue(parseInt(e.target.value))} />
<DoSomeMath value={inputValue} />
</>
);
}
export default App;
import './App.css';
import { memo, useCallback, useState } from 'react'
function MyButton2 ({onClick}) {
// 外部变化,每部都会被渲染一次
console.log('mybutton被执行')
return <button onClick={onClick}>子组件</button>
}
const MyButton = memo(function ({onClick}) {
// 外部变化,每部都会被渲染一次
console.log('mybutton被执行')
return <button onClick={onClick}>子组件</button>
})
function App() {
const [count, setCount] = useState(0)
const handleUpdate = () => setCount(count + 1)
// app 每次重新渲染,handleClick都是一个新的函数,依然会触发子组件更新
const handleClick2 = () => {
console.log('handleClick被点击...')
}
// 利用useCallback可以缓存住handleClick函数,成为记住组件
const handleClick = useCallback( () => {
console.log('handleClick被点击...')
}, [])
return (
<>
<p>Count: {count}</p>
<button onClick={handleUpdate}>点击</button>
<br/>
<MyButton onClick={handleClick}></MyButton>
</>
);
}
export default App;
[https://blog.csdn.net/qq_53123067/article/details/129707090]
import { makeAutoObservable, autorun, reaction, runInAction } from "mobx";
class Counter {
constructor(){
//makeAutoObservable的使用:makeAutoObservable就像加强版的makeObservable,默认情况下它将推断所有的属性,推断的规则为:所有的属性都成为observable,所有的方法都成为action,所有的计算属性都成为computed (计算属性接下来会讲到)。具体的使用如下:
// 参数1:target让对象变成可观察
// 参数2:排除属性和方法
// 参数3:指定自动绑定this
makeAutoObservable(this, {}, {autoBind: true})
}
count = 1;
increment(){
this.count++
}
incrementAsync(){
setTimeout(() => {
runInAction(() => {
this.count++
})
}, 1000);
}
decrement(){
this.count--
}
reset(){
this.count = 0
}
// 计算属性
get doubleCount() {
return this.count * 2
}
getDoubleCount() {
return this.count * 2
}
}
const counter = new Counter()
// 监听counter变化, 初始化会执行一次
autorun(() => {
console.log('监听count:', counter.count)
},)
// 监听数据的变化
//reaction类似于autorun,但可以更加精细地控制要跟踪的可观察对象,与autorun不同,reaction在初始化时不会自动运行。
// reaction接收两个参数,参数1:data函数,其返回值会作为第二个函数的输入;参数2:回调函数
reaction(() => counter.count, (value, oldValue) => {
console.log('count发生变化', value, oldValue)
})
export default counter
app.js
import './App.css';
import { memo, useCallback, useState } from 'react'
import { observer } from 'mobx-react-lite'
import counter from './store/counter';
// import counter2 from './store/counter';
function App() {
return (
<>
<h2>计数器案例</h2>
<div>点击次数:{counter.count}</div>
{/* 点击次数:{counter2.count} */}
<div>计算属性次数:{counter.doubleCount}</div>
<button onClick={()=>counter.increment()}>加1</button>
<button onClick={()=>counter.decrement()}>减1</button>
<button onClick={()=>counter.incrementAsync()}>异步加1</button>
<button onClick={()=>counter.reset()}>重置</button>
</>
);
}
export default observer(App);
import './App.css';
import React, {useContext } from 'react'
function App() {
const AppContext = React.createContext()
const A = () => {
const {name} = useContext(AppContext)
return (<p>A组件{name}嵌入了B<B/></p>)
}
const B = () => {
const {name} = useContext(AppContext)
return (<p>B组件{name}</p>)
}
return (
<AppContext.Provider value={{name: 'context值'}}>
<A></A>
</AppContext.Provider>
);
}
export default App;
useLayoutEffect() :和useEffect相同,都是用来执行副作用,但是它会在所有的DOM变更之后同步调用effect。useLayoutEffect和useEffect最大的区别就是一个是同步,一个是异步。
从这个Hook的名字上也可以看出,它主要用来读取DOM布局并触发同步渲染,在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。
官网建议还是尽可能的是使用标准的useEffec以避免阻塞视觉更新
import { useState,useEffect } from "react";
const usePerson = ({name}) => {
const [loading, setLoading] = useState(true)
const [person, setPerson] = useState({})
useEffect(() => {
setLoading(true)
setTimeout(()=> {
setLoading(false)
setPerson({name})
},2000)
},[name])
return [loading,person]
}
const AsyncPage = (name)=> {
const [loading,person] = usePerson(name)
return (
<>
{loading?<p>Loading...</p>:<p>{ person.name }</p>}
</>
)
}
const App = ()=> {
const [state,setState] = useState('')
const changeName = (name)=> {
setState(name)
}
return (
<>
<AsyncPage name={ state } />
<button onClick={ ()=> { changeName('郭靖')}}>郭靖</button>
<button onClick={ ()=> { changeName('黄蓉')}}>黄蓉</button>
</>
)
}
export default App;
//上面代码中,封装成了自己的Hooks,便于共享。其中,usePerson()为自定义Hooks它接受一个字符串,返回一个数组,数组中包括两个数据的状态,之后在使用usePerson()时,会根据传入的参数不同而返回不同的状态,然后很简便的应用于我们的页面中。
//这是一种非常简单的自定义Hook。如果项目大的话使用自定义Hook会抽离可以抽离公共代码,极大的减少我们的代码量,提高开发效率。
react router v6 获取传参需要用两个 hook,分别是 useParams(params)和 useSearchParams(search)
(1)useParams
params 传参
import { NavLink } from 'react-router-dom';
{/* 路由定义 /article/:id */}
<NavLink to={`/article/1`}>文章1</NavLink>
接收参数
import { useParams } from 'react-router-dom'
/* params */
const params = useParams();
const { id } = params;
(2)useSearchParams
search 传参
import { NavLink } from 'react-router-dom';
<NavLink to={`/article?id=1`}>文章1</NavLink>
接收参数
import { useSearchParams } from 'react-router-dom'
/* search */
let [searchParams, setSearchParams] = useSearchParams();
const { id } = searchParams;
(3)useLocation
state 传参
import { NavLink } from 'react-router-dom';
<NavLink to="/article" state={{ id: 1 }}>文章1</NavLink>
接收参数
import { useLocation } from 'react-router-dom'
let location = useLocation();
const { id } = location.state;
参考 [https://zhuanlan.zhihu.com/p/518339176]
useHistory 已废弃,而是使用 useNavigate
import { FC, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Button } from 'antd';
interface IndexProps{}
const Index: FC<IndexProps> = () => {
const navigate = useNavigate();
// 返回
const handleBack = () => navigate(-1);
// 前进
const handleForward = () => navigate(1);
// 刷新
const handleRefresh = () => navigate(0);
//
return <>
<Button type="primary" onClick={handleBack}>返回</Button>
<Button type="primary" onClick={handleForward}>前进</Button>
<Button type="primary" onClick={handleRefresh}>刷新</Button>
{/* 跳转路由 */}
<Button type="primary" onClick={() => navigate('/article/1', { replace: true })}>params</Button>
<Button type="primary" onClick={() => navigate('/article?id=1', { replace: true })}>search</Button>
<Button type="primary" onClick={() => navigate('/article', { replace: true, state: { id: 1 } })}>state</Button>
</>
}
export default Index;
//vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import path from 'path';
import {join} from 'node:path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src/')
// '@': join(__dirname, './src/')
}
}
})
//tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
},
"target": "ES2020",
......
}