十七、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的基本使用
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>)
}
}
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、路由的嵌套和重定向
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>)
}
}
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、编程式路由的跳转
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>);
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
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)
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、动态路由
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
import {PureComponent} from "react";
export default class Profile extends PureComponent {
render() {
return (<div>
Profile:{this.props.params.id}
</div>)
}
}
8、参数传递
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
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)
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的基本使用
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>)
}
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的使用
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>)
}
}
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("组件被销毁")
}
}, [])
}
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
}
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
(逻辑判断造成链表错乱,拿到的数据就会错乱)