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>
    {/* 
点击次数:{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);

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

你可能感兴趣的:(IT资源,react.js,学习,前端,reactjs,前端框架)