一路繁花似锦绣前程
失败的越多,成功才越有价值

导航

 

十七、react-router的使用

1、URL的hash
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue-router</title>
</head>
<body>
<a href="#/home">home</a>
<a href="#/about">about</a>
<div class="router-view"></div>
<script>
    const routerView = document.querySelector(".router-view")
    addEventListener("hashchange", () => {
        switch (location.hash) {
            case "#/home":
                routerView.innerHTML = "home"
                break;
            case "#/about":
                routerView.innerHTML = "about"
                break;
            default:
                routerView.innerHTML = "default"
        }
    })
</script>
</body>
</html>
2、HTML5的History
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue-router</title>
</head>
<body>
<a href="/home" onclick="routerHandler(event,this)">home</a>
<a href="/about" onclick="routerHandler(event,this)">about</a>
<div class="router-view"></div>
<script>
    const routerView = document.querySelector(".router-view")

    const changeContent = (pathname) => {
        switch (pathname) {
            case "/home":
                routerView.innerHTML = "home"
                break;
            case "/about":
                routerView.innerHTML = "about"
                break;
            default:
                routerView.innerHTML = "default"
        }
    }

    /**
     * 1、history接口是HTML5新增的,它有六种模式改变URL而不刷新页面
     *     - replaceState:替换原来的路径
     *     - pushState:使用新的路径
     *     - popState:路径的回退
     *     - go:向前或向后改变路径
     *     - forward:向前改变路径
     *     - back:向后改变路径
     */
    const routerHandler = (ev, el) => {
        ev.preventDefault()
        const href = el.getAttribute("href");
        history.pushState({}, "", href)
        changeContent(location.pathname)
    }

    addEventListener("popstate", changeContent)
</script>
</body>
</html>
3、router的基本使用
  • src/layout/App.js
import React, {PureComponent} from "react";
// npm i react-router-dom
import {HashRouter, Link, Routes, Route, Navigate} from "react-router-dom"
import routes from "@/routers"

/**
 * 1、BrowserRouter或HashRouter
 *     - Router中包含了对路径改变的监听,并且会将相应的路径传递给子组件
 *     - BrowserRouter使用history模式
 *     - HashRouter使用hash模式
 * 2、Link和NavLink
 *     - 通常路径的跳转是使用Link组件,最终会被渲染成a元素
 *     - NavLink是在Link基础之上增加了一些样式属性(后续学习)
 *     - to属性:Link中最重要的属性,用于设置跳转到的路径
 * 3、Route(V5)
 *     - Route用于路径的匹配
 *     - path属性:用于设置匹配到的路径
 *     - component属性:设置匹配到路径后,渲染的组件
 *     - exact:精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件
 * 4、Routes组件的作用
 *     - 路由排他
 *     - 替换V5的Switch
 * 5、Navigate组件的作用
 *     - 重定向
 *     - 替换V5的Redirect
 */
export default class App extends PureComponent {
  render() {
    return (<HashRouter>
      <Link to="/">首页</Link>
      <Link to="/about">关于</Link>
      <Link to="/profile/18">我的</Link>
      <Link to="/abc">错误</Link>
      <Routes>
        {
          routes.map(item => {
            return (<Route key={item.name}
                           path={item.path}
                           element={item.redirect ? <Navigate to={item.redirect}/> : <item.component/>}/>)
          })
        }
      </Routes>
    </HashRouter>)
  }
}
  • src/routers/index.js
import Home from "@/views/Home"
import About from "@/views/About"
import Profile from "@/views/Profile"
import NoMatch from "@/views/NoMatch"

const routes = [{
  name: "App",
  path: "/",
  redirect: "/home"
}, {
  name: "Home",
  path: "/home",
  component: Home
}, {
  name: "About",
  path: "/about",
  component: About
}, {
  name: "Profile",
  path: "/profile/:id",
  component: Profile
}, {
  name: "NoMatch",
  path: "/*",
  component: NoMatch
}]

export default routes
4、NavLink的使用
import React, {PureComponent} from "react";
import {HashRouter, NavLink, Routes, Route} from "react-router-dom"
import routes from "@/routers"

export default class App extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {}
  }

  render() {
    return (<HashRouter>
      <NavLink to="/"
               className={props => this.activeClassName(props)}
               style={props => this.activeStyle(props)}>首页</NavLink>
      <NavLink to="/about"
               className={props => this.activeClassName(props)}
               style={props => this.activeStyle(props)}>关于</NavLink>
      <NavLink to="/profile"
               className={props => this.activeClassName(props)}
               style={props => this.activeStyle(props)}>我的</NavLink>
      <Routes>
        {
          routes.map(item => {
            return (<Route key={item.name}
                           path={item.path}
                           element={<item.component/>}/>)
          })
        }
      </Routes>
    </HashRouter>)
  }

  activeClassName({isActive, isPending}) {
    return isActive ? "link-active" : ""
  }

  activeStyle({isActive, isPending}) {
    return isActive ? {color: "red"} : {}
  }
}
5、路由的嵌套和重定向
  • src/views/Home.js
import React, {PureComponent} from "react";
import {Link, Navigate, Route, Routes} from "react-router-dom";
import {homeChildren} from "@/routers";

export function HomeGoods(props) {
  return (<div>主页-商品</div>)
}

export function HomePrice(props) {
  return (<div>主页-价格</div>)
}

export default class Home extends PureComponent {
  render() {
    return (<div>
      <Link to="/home/goods">商品</Link>
      <Link to="/home/price">价格</Link>
      <Routes>
        {
          homeChildren.map(item => {
            return (<Route key={item.name}
                           path={item.path}
                           element={item.redirect ? <Navigate to={item.redirect}/> : <item.component/>}/>)
          })
        }
      </Routes>
    </div>)
  }
}
  • src/routers/index.js
import Home, {HomeGoods, HomePrice} from "@/views/Home"
import About from "@/views/About"
import Profile from "@/views/Profile"
import NoMatch from "@/views/NoMatch"

export const homeChildren = [{
  name: "Home",
  path: "*",
  redirect: "goods"
}, {
  name: "HomeGoods",
  path: "goods",
  component: HomeGoods,
}, {
  name: "HomePrice",
  path: "price",
  component: HomePrice,
}]

const routes = [{
  name: "App",
  path: "/",
  redirect: "/home"
}, {
  name: "Home",
  path: "/home/*",
  component: Home,
  children: homeChildren
}, {
  name: "About",
  path: "/about",
  component: About
}, {
  name: "Profile",
  path: "/profile/:id",
  component: Profile
}, {
  name: "NoMatch",
  path: "/*",
  component: NoMatch
}]

export default routes
6、编程式路由的跳转
  • src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './layout/App';
import store from "@/store";
import {Provider} from "react-redux"
import {HashRouter} from "react-router-dom"

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Provider store={store}>
  <HashRouter>
    <App/>
  </HashRouter>
</Provider>);
  • src/routers/index.js
import React from "react";
import {useNavigate} from "react-router-dom"
import Home, {HomeGoods, HomePrice} from "@/views/Home"
import About from "@/views/About"
import Profile from "@/views/Profile"
import NoMatch from "@/views/NoMatch"

/**
 * 1、利用高阶组件,将编程式跳转函数传入类组件
 * 2、组件必须是<Router/>的子组件
 */
export function withNavigate(WrappedComponent) {
  return function NavigateComponent(props) {
    const navigate = useNavigate()
    return <WrappedComponent navigate={navigate} {...props}/>
  }
}

export const homeChildren = [{
  name: "Home",
  path: "*",
  redirect: "goods"
}, {
  name: "HomeGoods",
  path: "goods",
  component: withNavigate(HomeGoods),
}, {
  name: "HomePrice",
  path: "price",
  component: withNavigate(HomePrice),
}]
const routes = [{
  name: "App",
  path: "/",
  redirect: "/home"
}, {
  name: "Home",
  path: "/home/*",
  component: withNavigate(Home),
  children: homeChildren
}, {
  name: "About",
  path: "/about",
  component: withNavigate(About)
}, {
  name: "Profile",
  path: "/profile/:id",
  component: withNavigate(Profile)
}, {
  name: "NoMatch",
  path: "/*",
  component: withNavigate(NoMatch)
}]
export default routes
  • src/layout/App.js
import React, {PureComponent} from "react";
import {Routes, Route, Navigate} from "react-router-dom"
import routes, {withNavigate} from "@/routers"

class App extends PureComponent {
  render() {
    return (<>
      <button onClick={e => this.props.navigate("/")}>首页</button>
      <button onClick={e => this.props.navigate("/about")}>关于</button>
      <button onClick={e => this.props.navigate("/profile/18")}>我的</button>
      <button onClick={e => this.props.navigate("/abc")}>错误</button>
      <Routes>
        {
          routes.map(item => {
            return (<Route key={item.name}
                           path={item.path}
                           element={item.redirect ? <Navigate to={item.redirect}/> : <item.component/>}/>)
          })
        }
      </Routes>
    </>)
  }
}

export default withNavigate(App)
  • src/views/Home.js
import React, {PureComponent} from "react";
import {Navigate, Route, Routes} from "react-router-dom";
import {homeChildren} from "@/routers";

export function HomeGoods(props) {
  return (<div>主页-商品</div>)
}

export function HomePrice(props) {
  return (<div>主页-价格</div>)
}

export default class Home extends PureComponent {
  render() {
    return (<div>
      <button onClick={e => this.props.navigate("/home/goods")}>商品</button>
      <button onClick={e => this.props.navigate("/home/price")}>价格</button>
      <Routes>
        {
          homeChildren.map(item => {
            return (<Route key={item.name}
                           path={item.path}
                           element={item.redirect ? <Navigate to={item.redirect}/> : <item.component/>}/>)
          })
        }
      </Routes>
    </div>)
  }
}
7、动态路由
  • src/routers/index.js
import React from "react";
import {useNavigate, useParams} from "react-router-dom"
import Home, {HomeGoods, HomePrice} from "@/views/Home"
import About from "@/views/About"
import Profile from "@/views/Profile"
import NoMatch from "@/views/NoMatch"

export function withNavigate(WrappedComponent) {
  return function NavigateComponent(props) {
    const navigate = useNavigate()
    const params = useParams()
    return <WrappedComponent navigate={navigate} params={params} {...props}/>
  }
}

export const homeChildren = [{
  name: "Home",
  path: "*",
  redirect: "goods"
}, {
  name: "HomeGoods",
  path: "goods",
  component: withNavigate(HomeGoods),
}, {
  name: "HomePrice",
  path: "price",
  component: withNavigate(HomePrice),
}]
const routes = [{
  name: "App",
  path: "/",
  redirect: "/home"
}, {
  name: "Home",
  path: "/home/*",
  component: withNavigate(Home),
  children: homeChildren
}, {
  name: "About",
  path: "/about",
  component: withNavigate(About)
}, {
  name: "Profile",
  path: "/profile/:id",
  component: withNavigate(Profile)
}, {
  name: "NoMatch",
  path: "/*",
  component: withNavigate(NoMatch)
}]
export default routes
  • src/views/Profile.js
import {PureComponent} from "react";

export default class Profile extends PureComponent {
  render() {
    return (<div>
      Profile:{this.props.params.id}
    </div>)
  }
}
8、参数传递
  • src/routers/index.js
import React from "react";
import {useNavigate, useParams, useLocation} from "react-router-dom"
import Home, {HomeGoods, HomePrice} from "@/views/Home"
import About from "@/views/About"
import Profile from "@/views/Profile"
import NoMatch from "@/views/NoMatch"

export function withNavigate(WrappedComponent) {
  return function NavigateComponent(props) {
    const navigate = useNavigate()
    const params = useParams()
    const location = useLocation()
    return <WrappedComponent navigate={navigate} params={params}
                             location={location} {...props}/>
  }
}

export const homeChildren = [{
  name: "Home",
  path: "*",
  redirect: "goods"
}, {
  name: "HomeGoods",
  path: "goods",
  component: withNavigate(HomeGoods),
}, {
  name: "HomePrice",
  path: "price",
  component: withNavigate(HomePrice),
}]
const routes = [{
  name: "App",
  path: "/",
  redirect: "/home"
}, {
  name: "Home",
  path: "/home/*",
  component: withNavigate(Home),
  children: homeChildren
}, {
  name: "About",
  path: "/about",
  component: withNavigate(About)
}, {
  name: "Profile",
  path: "/profile/:id",
  component: withNavigate(Profile)
}, {
  name: "NoMatch",
  path: "/*",
  component: withNavigate(NoMatch)
}]
export default routes
  • src/layout/App.js
import React, {PureComponent} from "react";
import {Routes, Route, Navigate, NavLink} from "react-router-dom"
import routes, {withNavigate} from "@/routers"

class App extends PureComponent {
  render() {
    return (<>
      <button onClick={e => this.props.navigate("/")}>首页</button>
      <NavLink to={{pathname: "/about", search: "name=tly"}} state={{age: 18}}>
        <button>关于</button>
      </NavLink>
      <button onClick={e => this.props.navigate("/profile/18")}>我的</button>
      <button onClick={e => this.props.navigate("/abc?name=htt", {state: {age: 20}})}>错误</button>
      <Routes>
        {
          routes.map(item => {
            return (<Route key={item.name}
                           path={item.path}
                           element={item.redirect ? <Navigate to={item.redirect}/> : <item.component/>}/>)
          })
        }
      </Routes>
    </>)
  }
}

export default withNavigate(App)
  • src/views/About.js
import {PureComponent} from "react";

export default class About extends PureComponent {
  render() {
    console.log(this.props.location)
    return (<div>
      About
    </div>)
  }
}
9、react-router-config(了解)
* 目前我们所有的路由定义都是直接使用Route组件,并且添加属性来完成的
* 但是这样的方式会让路由变得非常混乱,我们希望将所有的路由配置放到一个地方进行集中管理
    - 这个时候可以使用react-router-config来完成
* 安装react-router-config
    - npm i react-router-config
* 配置路由映射的关系数组
########
const routes = [{
  path: "/",
  exact: true,
  component: Home
}, {
  path: "/about",
  component: About,
  routes: [{}]
}]
########
* 使用renderRoutes函数完成配置
    - {renderRoutes(routes)}

十八、Hooks的使用

1、计数器案例
import React, {useState} from "react";

/**
 * 1、useState函数
 *     - 参数:作用是给创建出来的状态一个默认值
 *     - 返回值:数组
 *         ~ 元素1:当前state的值
 *         ~ 元素2:设置新的值时,使用的一个函数
 */
export default function App() {
  const arr = useState(0)
  const state = arr[0]
  const setState = arr[1]
  return (<div>
    <h2>当前计数:{state}</h2>
    <button onClick={e => setState(state + 1)}>+1</button>
    <button onClick={e => setState(state - 1)}>-1</button>
  </div>)
}
2、复杂状态的修改
import React, {useState} from "react";

export default function App() {
  /**
   * 1、const [state, setState] = useState(默认值); setState(newState)
   *     - setState中会判断state===newState,不等才会触发组件更新
   */
  const [list, setList] = useState([])
  const [name, setName] = useState("")
  const [age, setAge] = useState("")

  function itemChage(item) {
    item.age -= 5
    setList([...list])
  }

  return (<div>
    姓名:<input type="text" onChange={e => setName(e.target.value)}/>
    年龄:<input type="text" onChange={e => setAge(e.target.value)}/>
    <button onClick={e => setList([...list, {id: Date.now(), name, age}])}>添加</button>
    <ul>{list.map(item => {
      return (<li key={item.id}>
        {item.name}-{item.age}
        <button onClick={e => itemChage(item)}>-5岁</button>
        <button onClick={e => setList(list.filter(itemx => item !== itemx))}>删除</button>
      </li>)
    })}</ul>
  </div>)
}
3、useState的使用补充说明
import React, {useState} from "react";

export default function App() {
  // 1、默认值可以是函数
  const [age, setAge] = useState(() => 0)

  function addAge() {
    for (let i = 0; i < 5; i++) {
      /**
       * 2、参数如果是函数,则会取累加的i。
       *   参数如果不是函数,则会取循环的最后一个i。
       *   组件都只更新一次
       */
      // setAge(age + i) // 4
      setAge(prevAge => prevAge + i) // 10
    }
  }

  return (<div>
    <button onClick={e => addAge()}>添加</button>
    <div>{age}</div>
  </div>)
}
4、useEffect的基本使用
  • 未传入参数2
import React, {useState, useEffect} from "react";

export default function App() {
  const [age, setAge] = useState(() => 0)

  /**
   * 1、参数1函数:相当于组件生命周期的挂载和更新
   * 2、注意:不要在参数1函数内使用setState,会死循环
   */
  useEffect(() => {
    console.log(age)
  })

  return (<div>
    <button onClick={e => setAge(age + 10)}>添加</button>
    <div>{age}</div>
  </div>)
}
  • 传入参数2
import React, {useState, useEffect} from "react";

export default function App() {
  const [display, setDisplay] = useState(true)
  return (<div>
    <button onClick={e => setDisplay(!display)}>显示/隐藏</button>
    {display && <Home/>}
  </div>)
}

function Home() {
  const [age, setAge] = useState(() => 0)

  /**
   * 1、参数1函数:相当于组件生命周期的挂载
   * 2、参数1函数返回值函数:相当于组件生命周期的卸载
   * 3、参数2:是一个数组
   */
  useEffect(() => {
    console.log("订阅事件")
    return () => {
      console.log("取消订阅")
    }
  }, [])

  return (<div>
    <button onClick={e => setAge(age + 10)}>添加</button>
    <div>{age}</div>
  </div>)
}
5、多个useEffect一起使用
import React, {useState, useEffect} from "react";

export default function App() {
  const [display, setDisplay] = useState(true)
  const [count, setCount] = useState(0)
  useEffect(() => {
    console.log("参数2不传:则组件挂载时会执行一次,任何state更新时会执行一次")
  })
  useEffect(() => {
    console.log("参数2传空数组:则组件挂载时会执行一次,任何state更新时都不会执行")
  }, [])
  useEffect(() => {
    console.log("参数2传含display的数组:则组件挂载时会执行一次,display更新时会执行一次")
  }, [display])
  return (<div>
    <button onClick={e => setDisplay(!display)}>显示/隐藏</button>
    <div>{display ? "显示" : "隐藏"}</div>
    <button onClick={e => setCount(count + 10)}>+10</button>
    <div>{count}</div>
  </div>)
}
6、useContext的使用
import React, {createContext, useContext} from "react";

const UserContext = createContext(null)
const ThemeContext = createContext(null)

export default function App() {
  return (<UserContext.Provider value={{name: "莱恩", age: 18}}>
    <ThemeContext.Provider value={{fontSize: "16px", color: "black"}}>
      <Home/>
    </ThemeContext.Provider>
  </UserContext.Provider>)
}

function Home() {
  const user = useContext(UserContext)
  const theme = useContext(ThemeContext)
  console.log(user)
  console.log(theme)
  return (<div>
    Home
  </div>)
}
7、useReducer的使用
import React, {useReducer} from "react";

function counterReducer(state, action) {
  switch (action.type) {
    case "increment":
      return {...state, counter: state.counter + 1}
    case "decrement":
      return {...state, counter: state.counter - 1}
    default:
      return state
  }
}

export default function App() {
  const [state, dispatch] = useReducer(counterReducer, {counter: 0})
  return (<div>
    <h2>当前计数:{state.counter}</h2>
    <button onClick={e => dispatch({type: "increment"})}>+1</button>
    <button onClick={e => dispatch({type: "decrement"})}>-1</button>
  </div>)
}
8、useCallback的使用
import React, {useState, useCallback, memo} from "react";

export default function App() {
  const [count, setCount] = useState(0)
  const [display, setDisplay] = useState(true)

  /**
   * 1、count发生变化时,useCallback函数会返回一个新的changeCount函数。
   *   count未发生变化,useCallback函数返回的是原来的changeCount函数。
   *   props未发生变化,则组件不会更新。
   */
  const changeCount = useCallback(() => {
    setCount(count + 1)
  }, [count])

  const changeDispaly = () => {
    setDisplay(!display)
  }

  console.log(`渲染:App`)
  return (<div>
    <ButtonComponent text="changeCount" clickEvent={changeCount}/>
    <div>{count}</div>
    <ButtonComponent text="changeDispaly" clickEvent={changeDispaly}/>
    <div>{String(display)}</div>
  </div>)
}

const ButtonComponent = memo(function (props) {
  console.log(`渲染:ButtonComponent-${props.text}`)
  return (<button onClick={props.clickEvent}>{props.text}</button>)
})
9、useMemo的使用
import React, {useState, useMemo, memo} from "react";

export default function App() {
  const [count, setCount] = useState(0)

  // const info = {name: "神灵"}
  /**
   * 1、参数2中有state发生变化,则useMemo函数会返回一个新的info
   * 2、useMemo参数1函数返回的是一个函数,相当于useCallback功能
   */
  const info = useMemo(() => {
    return {name: "神灵"}
  }, [])

  return (<div>
    <button onClick={e => setCount(count + 1)}>+1</button>
    <div>{count}</div>
    <Home info={info}/>
  </div>)
}

const Home = memo(function (props) {
  console.log("渲染")
  return (<div>{props.info.name}</div>)
})
10、useRef的使用
  • 获取DOM和组件实例
import React, {useRef, PureComponent} from "react";

export default function App() {
  const inputRef = useRef()
  // 必须是class组件
  const homeRef = useRef()

  function changeInput() {
    inputRef.current.value = Date.now()
  }

  function getHome() {
    console.log(homeRef.current.state)
  }

  return (<div>
    <input ref={inputRef} type="text"/>
    <Home ref={homeRef}/>
    <button onClick={changeInput}>获取DOM</button>
    <button onClick={getHome}>获取组件实例</button>
  </div>)
}

class Home extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      name: "混沌骑士"
    }
  }

  render() {
    return (<div>Home</div>)
  }
}
  • 获取上一次的state(案例)
import React, {useRef, useState, useEffect} from "react";

export default function App() {
  const [count, setCount] = useState(0)

  const countRef = useRef(count)
  useEffect(() => {
    /**
     * 1、执行时机:jsx实例化之后,jsx渲染之前
     * 2、current的变化并不会引起jsx的变化
     */
    countRef.current = count
  }, [count])

  return (<div>
    <div>最新:{count}</div>
    <div>上一次:{countRef.current}</div>
    <button onClick={e => setCount(Math.floor(Math.random() * 100))}>获取组件实例</button>
  </div>)
}
11、forwardRef的使用
import React, {useRef, forwardRef} from "react";

const Home = forwardRef((props, ref) => {
  return (<div>
    <input ref={ref} type="text"/>
  </div>)
})

export default function App() {
  const inputRef = useRef(null)

  return (<div>
    <Home ref={inputRef}/>
    <button onClick={e => inputRef.current.focus()}>按钮</button>
  </div>)
}
12、useImperativeHandle的使用
import React, {useRef, forwardRef, useImperativeHandle} from "react";

const Home = forwardRef((props, ref) => {
  const inputRef = useRef(null)

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus()
    }
  }), [])

  return (<div>
    <input ref={inputRef} type="text"/>
  </div>)
})

export default function App() {
  const inputRef = useRef(null)

  return (<div>
    <Home ref={inputRef}/>
    <button onClick={e => inputRef.current.focus()}>按钮</button>
  </div>)
}
13、useLayoutEffect的使用
import React, {useState, useEffect, useLayoutEffect} from "react";

export default function App() {
  const [count, setCount] = useState(10)

  /**
   * 1、通过alert方式测试useEffect和useLayoutEffect区别
   *     - useEffect的count页面显示顺序:10 -> 0 -> 20
   *     - useLayoutEffect的count页面显示顺序:10 -> 20
   */
  useLayoutEffect(() => {
    alert("阻塞")
    if (count === 0) {
      setCount(20)
    }
  }, [count])

  return (<div>
    <div>{count}</div>
    <button onClick={e => setCount(0)}>按钮</button>
  </div>)
}
14、自定义hook
  • 基本使用
import React, {useState, useEffect} from "react";

export default function App() {
  const [display, setDisplay] = useState(true);

  return (<div>
    <button onClick={e => setDisplay(!display)}>按钮</button>
    {display && <Home/>}
  </div>)
}

function Home() {
  useLifeCycle()

  return (<div>Home</div>)
}

/**
 * 1、自定义hook命名要求
 *     - use + 首字母大写的函数名
 */
function useLifeCycle() {
  useEffect(() => {
    console.log("组件被创建")
    return () => {
      console.log("组件被销毁")
    }
  }, [])
}
  • 共享context(案例)
import React, {createContext, useContext} from "react";

const UserContext = createContext(null)
const ThemeContext = createContext(null)

export default function App() {
  return (<UserContext.Provider value={{name: "大鱼人"}}>
    <ThemeContext.Provider value={{color: "red"}}>
      <Home/>
    </ThemeContext.Provider>
  </UserContext.Provider>)
}

function Home() {
  const {user, theme} = useShareContext()
  return (<div>
    <div>姓名:{user.name}</div>
    <div>颜色:{theme.color}</div>
  </div>)
}

function useShareContext() {
  return {
    user: useContext(UserContext),
    theme: useContext(ThemeContext)
  }
}
  • 获取滚动位置(案例)
import React, {useState, useEffect} from "react";

export default function App() {
  const scrollPosition = useScrollPosition()

  return (<div style={{height: "2000px"}}>
    <div style={{position: "fixed"}}>滚动高度:{scrollPosition}</div>
  </div>)
}

function useScrollPosition() {
  const [scrollPosition, setScrollPosition] = useState(0);

  useEffect(() => {
    const handleScroll = () => {
      setScrollPosition(window.scrollY)
    }
    document.addEventListener("scroll", handleScroll)
    return () => {
      document.removeEventListener("scroll", handleScroll)
    }
  }, [])

  return scrollPosition
}
  • localStorage存储(案例)
import React, {useState, useEffect} from "react";

export default function App() {
  const [data, setData] = useLocalStorage("vuex")

  return (<div>
    <div>localStorage:{data}</div>
    <button onClick={e => setData("小鱼人")}>设置</button>
  </div>)
}

function useLocalStorage(key) {
  const [data, setData] = useState(() => {
    return JSON.parse(window.localStorage.getItem(key))
  });

  useEffect(() => {
    window.localStorage.setItem(key, JSON.stringify(data))
  }, [data, key])

  return [data, setData]
}
15、fiber原理
* window.requestIdleCallback()方法
    - 参数1:是一个函数,该函数将在浏览器空闲时期被调用
    - 参数2({timeout:正值}):可选
16、hook原理
* 多个hook是以链表形式保存的,所以不允许在逻辑判断里使用hook
  (逻辑判断造成链表错乱,拿到的数据就会错乱)
posted on 2023-01-15 23:18  一路繁花似锦绣前程  阅读(34)  评论(0编辑  收藏  举报