React 基础学习02

以下是React18版本的基础学习资源
点击我获取更多学习资源

1. …模板扩展符

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;

2. 模板扩展发嵌套使用

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;

3. 默认插槽

import './App.css';

function List({
    children}) {
   
  return (
    <ul>
      {
   children}
    </ul>
  )
}
function App() {
   

  return (
    <>
    <List>
      <li>列表1</li>
      <li>列表2</li>
    </List>
    </>
  );
}

export default App;

4. 带名字插槽

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;

5. 子调用父

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;

6. useReducer作用

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;

7. 父调用子 forwardRef, useImperativeHandle, useRef

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;

8. useEffect 作用

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;

9. useMemo缓存数据,避免重复计算

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;

10. memo 记忆组件和useCallback记忆函数

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;

11. mobx

[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>
    {
   /* <div>点击次数:{counter2.count}</div> */}
    <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);

12. useEffect 第二个参数详解

  1. undefined: 任何状态改变都会执行
  2. 不是数组:报警
  3. 是空数组: 回调只会再函数组件调用执行一次(类似mounted)
  4. 是有元素的数组:元素为状态的话,状态更新,回调测重新执行一次

13. createContext作用

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;

14. LayoutEffect Hook

useLayoutEffect() :和useEffect相同,都是用来执行副作用,但是它会在所有的DOM变更之后同步调用effect。useLayoutEffect和useEffect最大的区别就是一个是同步,一个是异步。

从这个Hook的名字上也可以看出,它主要用来读取DOM布局并触发同步渲染,在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

官网建议还是尽可能的是使用标准的useEffec以避免阻塞视觉更新

15. 自定义组件

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会抽离可以抽离公共代码,极大的减少我们的代码量,提高开发效率。

16. 路由传参三种方式

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;

17. 路由跳转

参考 [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;

18. 配置路径别名

//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",
    ......
  }

相关推荐

  1. React 基础学习02

    2024-01-31 13:02:01       30 阅读
  2. React 基础学习01

    2024-01-31 13:02:01       43 阅读
  3. 02-python基础学习

    2024-01-31 13:02:01       39 阅读
  4. 03 React 基础样式控制

    2024-01-31 13:02:01       15 阅读
  5. HarmonyOS ArkUI基础学习02

    2024-01-31 13:02:01       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-31 13:02:01       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-31 13:02:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-31 13:02:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-31 13:02:01       18 阅读

热门阅读

  1. 2024/1/30 备战蓝桥杯 3-1 栈

    2024-01-31 13:02:01       36 阅读
  2. arch linux上安装docker

    2024-01-31 13:02:01       33 阅读
  3. docker 的常用命令

    2024-01-31 13:02:01       32 阅读
  4. Reactor简述

    2024-01-31 13:02:01       27 阅读
  5. 四、概要设计说明书(软件工程)

    2024-01-31 13:02:01       26 阅读
  6. C语言K&R圣经笔记 6.8联合体 6.9位域

    2024-01-31 13:02:01       33 阅读
  7. docker 的常用命令

    2024-01-31 13:02:01       29 阅读
  8. 【二叉树专题】最大二叉树

    2024-01-31 13:02:01       27 阅读
  9. RabbitMQ和Kafka对比

    2024-01-31 13:02:01       28 阅读