一篇文章带你走进react的大门,组件、hook、api详解

react PC端项目构建TS,react@18.2.0+antd+vite+axios+redux+sass+ts 完整版代码下载:
https://download.youkuaiyun.com/download/randy521520/88922625
react PC端项目构建,react@18.2.0+antd+vite+axios+redux+sass完整版代码下载:
https://download.youkuaiyun.com/download/randy521520/88922569
react移动端项目构建TS,react@18.2.0+react-vant+vite+axios+redux+sass+ts完整版代码下载:
https://download.youkuaiyun.com/download/randy521520/88917557
react移动端项目构建,react@18.2.0+react-vant+vite+axios+redux+sass完整版代码下载:
https://download.youkuaiyun.com/download/randy521520/88917543

一、react简介

React 是由 Facebook 开发的一款用于构建用户界面的 JavaScript 库。它主要专注于构建单页面应用程序(SPA)中的用户界面,采用组件化的开发方式,使得开发者能够更轻松地构建交互式、动态的前端界面。本文主要将React@18.2.0版本,由于React 官方文档通常更倾向于推荐函数组件和 Hooks 的使用,这这里主要介绍函数组件
以下是 React 的一些主要特点和优势:
1.组件化开发:React 鼓励开发者将界面拆分成独立的组件,每个组件负责管理自己的状态和 UI 显示。这种组件化开发方式使得代码更易于维护、复用和测试。
2.虚拟 DOM:React 使用虚拟 DOM 技术来提高性能。通过在内存中维护一颗虚拟 DOM 树,React 能够高效地比对前后两次状态的差异,并只更新必要的部分,从而减少对实际 DOM 的操作,提升页面渲染性能。
3.单向数据流:React 遵循单向数据流的原则,数据的流动是单向的,从父组件传递给子组件。这种数据流清晰明了,易于追踪数据的变化,减少了出现 bug 的可能性。
4.JSX 语法:React 使用 JSX 语法,允许在 JavaScript 代码中编写类似 HTML 的标记,使得 UI 代码更加直观和易读。
5.生命周期方法:React 提供了一系列生命周期方法,允许开发者在组件的不同阶段执行特定的逻辑,例如组件挂载时、更新时、卸载时等。
6.社区支持:React 拥有庞大的开发者社区和生态系统,提供了丰富的第三方库和工具,帮助开发者更高效地构建 React 应用。

二、react Hook之useState

useState管理组件状态,实现双向数据绑定,类似class组件种的this.state,用法useState(value);

import {useState} from "react";

const Home = () => {
    let [count, setCount] = useState(0);

    const onCountChange = () => {
        count++;
        setCount(count);
    }
    
    return (<>
        <div onClick={onCountChange}>改变Count</div>
        <div>页面渲染次数:{count}</div>
    </>)
}

export default Home;
三、react Hook之useEffect

useEffect用于在函数组件中执行副作用操作。副作用是指除了渲染界面之外对组件外部环境产生影响的操作,比如数据获取、订阅事件、手动操作 DOM 等,类似class组件种的生命周期。接受两个参数fn、dependencies,用法useEffect(fn,dependencies);类似的组件还有useLayoutEffect、useInsertionEffect。useLayoutEffect是useEffect 的一个版本,在浏览器重新绘制屏幕之前触发。useLayoutEffect 可能会影响性能。尽可能使用 useEffect;useInsertionEffect是为 CSS-in-JS 库特意打造的,除非你正在使用 CSS-in-JS 库并且需要注入样式,否则应该使用 useEffect 或者 useLayoutEffect。
1.组件生命周期之组件初始化

import {useEffect} from "react";

const Home = () => {
    useEffect(() => {
        console.log('组件初始化')
    }, []);

    return (<></>)
}

export default Home;

2.组件生命周期之组件卸载

import {useEffect} from "react";

const Home = () => {
    useEffect(() => {
        return ()=>{
            console.log('组件卸载')
        }
    }, []);

    return (<></>)
}

export default Home;

3.组件生命周期之组件props改变

import React, {useEffect, useState} from "react";

/******************子组件**********************/
const _Content = (props) => {

    useEffect(() => {
        console.log('组件props改变')
    }, [props]);

    return (<div>content页</div>)
};

const Content = React.memo(_Content)


/******************父组件**********************/
const Home = () => {
    let [count, setCount] = useState(0);

    const onCountChange = () => {
        count++;
        setCount(count);
    }

    return (<>
        <div onClick={onCountChange}>改变Count</div>
        <div>页面渲染次数:{count}</div>
        <Content content={count}></Content>
    </>)
}

export default Home;

4.组件生命周期之组件state改变

import {useEffect, useState} from "react";

const Home = () => {
    let [count, setCount] = useState(0);

    const onCountChange = () => {
        count++;
        setCount(count);
    }

    useEffect(()=>{
        console.log('count改变')
    },[count])

    return (<>
        <div onClick={onCountChange}>改变Count</div>
        <div>页面渲染次数:{count}</div>
    </>)
}

export default Home;
四、react Hook之useCallback

useCallback在多次渲染中缓存函数,接受两个参数fn、dependencies,用法useCallback(fn,dependencies);

  • fn:缓存的函数。此函数可以接受任何参数并且返回任何值。只会在初次渲染时返回此函数,当下一次渲染时,如果dependencies相比于上一次渲染时没有改变,那么将会返回相同的函数
  • dependencies:是否更新 fn 的所有响应式值的一个列表。响应式值包括 props、state,和所有在你组件内部直接声明的变量和函数。
    1.使用场景一:将函数传递给子组件,跳过组件的重新渲染。常和memo一起优化性能
  • 不使用useCallback,向子组件传递函数;每次点击onContentClick时,子组件都会重新渲染,但是onContentClick没变化,子组件应不会重新渲染,这是因为父组件重新渲染时onContentClick始终是不同的,导致memo性能优化没生效
import React, {useState} from "react";

/******************子组件**********************/
const _Content = ({onClick})=>{
    console.log('子组件重新渲染')
    return (<div onClick={onClick}>content页</div>)
};

const Content = React.memo(_Content)

/******************父组件**********************/
const Home = ()=>{
    let [count,setCount] = useState(0);
    const onContentClick = ()=>{
        count++;
        setCount(count)
    }

    return (<>
        <Content onClick={onContentClick}></Content>
        <div>父组件渲染次数:{count}</div>
    </>)
}

export default Home;

在这里插入图片描述

  • 使用useCallback,向子组件传递函数;使用useCallback后父组件重新渲染了,子组件未重新渲染,达到了优化效果;如果在useCallback中传入[content],那么content变化,onContentClick 也会改变,子组件就会重新渲染
import React, {useCallback, useState} from "react";

/******************子组件**********************/
const _Content = ({onClick})=>{
    console.log('子组件重新渲染')
    return (<div onClick={onClick}>content页</div>)
};

const Content = React.memo(_Content)

/******************父组件**********************/
const Home = ()=>{
    let [count,setCount] = useState(0);
    const onContentClick = useCallback(()=>{
        count++;
        setCount(count)
    },[])

    return (<>
        <Content onClick={onContentClick}></Content>
        <div>父组件渲染次数:{count}</div>
    </>)
}

export default Home;

在这里插入图片描述
2.使用场景二:防止频繁触发Effect ,假如有这样的一个功能:需要在一个组件连接一个Websocket,每次Websocket的id改变,就断开之前的连接重新连接

  • 不使用useCallback,由图可以看出roomId没改变,Websocket会反复连接端口
import React, {useCallback, useEffect, useState} from "react";

/******************子组件**********************/
const _Content = ({count, roomId}) => {
    const createWebsocketOptions = () => {
        return {
            serverUrl: 'https://localhost:1234',
            roomId: roomId
        };
    };

    useEffect(() => {
        const options = createWebsocketOptions();
        console.log(options);
        return () => {
            console.log(`断开之前的连接${options.roomId}`)
        }
    }, [createWebsocketOptions]);

    return (<div>content页</div>)
};

const Content = React.memo(_Content)


/******************父组件**********************/
const Home = () => {
    let [count, setCount] = useState(0);
    let [roomId, setRoomId] = useState(1000);

    const onCountChange = () => {
        count++;
        setCount(count);
    }

    const onRoomIdChange = () => {
        roomId++;
        setRoomId(roomId);
    }

    return (<>
        <div onClick={onCountChange}>改变Count</div>
        <div onClick={onRoomIdChange}>改变RoomId</div>
        <div>页面渲染次数:{count}</div>
        <div>Websocket ID:{roomId}</div>
        <Content content={count} roomId={roomId}></Content>
    </>)
}

export default Home;

在这里插入图片描述

  • 使用useCallback,只有roomId改变,Websocket才会端口旧的,连接新的;只是示例说明useCallback使用场景,直接使用useEffect来处理roomId的改变也是可以的
    import React, {useCallback, useEffect, useState} from “react”;
import React, {useCallback, useEffect, useState} from "react";

/******************子组件**********************/
const _Content = ({count, roomId}) => {
    const createWebsocketOptions = useCallback(() => {
        return {
            serverUrl: 'https://localhost:1234',
            roomId: roomId
        };
    },[roomId]);

    useEffect(() => {
        const options = createWebsocketOptions();
        console.log(options);
        return () => {
            console.log(`断开之前的连接${options.roomId}`)
        }
    }, [createWebsocketOptions]);

    return (<div>content页</div>)
};

const Content = React.memo(_Content)


/******************父组件**********************/
const Home = () => {
    let [count, setCount] = useState(0);
    let [roomId, setRoomId] = useState(1000);

    const onCountChange = () => {
        count++;
        setCount(count);
    }

    const onRoomIdChange = () => {
        roomId++;
        setRoomId(roomId);
    }

    return (<>
        <div onClick={onCountChange}>改变Count</div>
        <div onClick={onRoomIdChange}>改变RoomId</div>
        <div>页面渲染次数:{count}</div>
        <div>Websocket ID:{roomId}</div>
        <Content content={count} roomId={roomId}></Content>
    </>)
}

export default Home;

在这里插入图片描述
3.使用场景三:优化自定义 Hook,建议将hook返回的任何函数包裹在 useCallback 中,可以保证使用者在需要时能够优化自己的代码。

import {useCallback,useState} from "react";

function useRouter() {
    let [params, setCountParams] = useState({});

    const navigate = useCallback((url) => {
        setCountParams({ type: 'navigate', url });
    }, [count]);

    const goBack = useCallback(() => {
        setCountParams({ type: 'back' });
    }, [count]);

    return {
        navigate,
        goBack,
    };
}

4.使用场景四:从记忆化回调中更新 state,不使用useCallback包裹,每次组件重新渲染时都会创建一个新的函数,会导致不必要的性能损失;使用useCallback,避免不必要的函数重新创建

import {useCallback, useState} from "react";

const Home = () => {
    let [count, setCount] = useState(0);

    const onCountChange = useCallback(() => {
        count++;
        setCount(count);
    },[count])

    return (<>
        <div onClick={onCountChange}>改变Count</div>
        <div>页面渲染次数:{count}</div>
    </>)
}

export default Home;
五、react Hook之useMemo

useMemo用于在函数组件中进行性能优化。它可以缓存计算结果并在依赖项发生变化时重新计算,从而避免不必要的重复计算,用法useMemo(fn,dependencies);
1.使用场景一:避免代价昂贵的重新计算

  • 不使用useMemo,由图可以看出每次count改变,都会重复调用filterTodos
import {useEffect, useState} from "react";

const Home = () => {
    let [count, setCount] = useState(0);
    let [todo, setTodo] = useState([1, 2, 3, 4, 3, 5, 4]);
    const onContentChange = () => {
        count++;
        setCount(count)
    }
    const onTodoChange = () => {
        todo.push(Math.floor(Math.random() * 17) + 3);
        setTodo([...todo])
    }

    const filterTodos = (todos) => {
        return [...new Set(todos.filter(element => element > 2).sort())];
    }

    const visibleTodos = filterTodos(todo);

    useEffect(() => {
        console.log('过滤后的值:', visibleTodos)
    }, [visibleTodos]);

    return (<>
        <div onClick={onContentChange}>改变content</div>
        <div onClick={onTodoChange}>改变todo</div>
        <div>父组件渲染次数:{count}</div>
        <div>todo值:{todo.join(',')}</div>
        <div>visibleTodos值:{visibleTodos.join(',')}</div>
    </>)
}

export default Home;

在这里插入图片描述

  • 使用useMemo,count改变不会影响visibleTodos计算
import {useEffect, useMemo, useState} from "react";

const Home = () => {
    let [count, setCount] = useState(0);
    let [todo, setTodo] = useState([1, 2, 3, 4, 3, 5, 4]);
    const onContentChange = () => {
        count++;
        setCount(count)
    }
    const onTodoChange = () => {
        todo.push(Math.floor(Math.random() * 17) + 3);
        setTodo([...todo])
    }

    const filterTodos = (todos) => {
        return [...new Set(todos.filter(element => element > 2).sort())];
    }

    const visibleTodos = useMemo(()=>filterTodos(todo),[todo]);

    useEffect(() => {
        console.log('过滤后的值:', visibleTodos)
    }, [visibleTodos]);

    return (<>
        <div onClick={onContentChange}>改变content</div>
        <div onClick={onTodoChange}>改变todo</div>
        <div>父组件渲染次数:{count}</div>
        <div>todo值:{todo.join(',')}</div>
        <div>visibleTodos值:{visibleTodos.join(',')}</div>
    </>)
}

export default Home;

在这里插入图片描述
2.场景二:避免组件的重新渲染

  • 不使用useMemo,由图可以看出content组件的其他props改变,都会调用filterTodos
import React, {useEffect, useState} from "react";

/******************子组件**********************/
const _Content = ({count,todos}) => {
    const filterTodos = (todos) => {
        return [...new Set(todos.filter(element => element > 2).sort())];
    }

    const visibleTodos = filterTodos(todos);

    useEffect(() => {
        console.log('过滤后的值:', visibleTodos)
    }, [visibleTodos]);

    return (<div>content页</div>)
};

const Content = React.memo(_Content)


/******************父组件**********************/
const Home = () => {
    let [count, setCount] = useState(0);
    let [todo, setTodo] = useState([1, 2, 3, 4, 3, 5, 4]);
    const onContentChange = () => {
        count++;
        setCount(count)
    }
    const onTodoChange = () => {
        todo.push(Math.floor(Math.random() * 17) + 3);
        setTodo([...todo])
    }

    return (<>
        <div onClick={onContentChange}>改变content</div>
        <div onClick={onTodoChange}>改变todo</div>
        <div>父组件渲染次数:{count}</div>
        <Content count={count} todos={todo}></Content>
    </>)
}

export default Home;

在这里插入图片描述

  • 使用useMemo,由图可以看出content组件的其他props改变,不会调用filterTodos
import React, {useEffect, useMemo, useState} from "react";

/******************子组件**********************/
const _Content = ({count,todos}) => {
    const filterTodos = (todos) => {
        return [...new Set(todos.filter(element => element > 2).sort())];
    }

    const visibleTodos = useMemo(()=>filterTodos(todos),[todos]);

    useEffect(() => {
        console.log('过滤后的值:', visibleTodos)
    }, [visibleTodos]);

    return (<div>content页</div>)
};

const Content = React.memo(_Content)


/******************父组件**********************/
const Home = () => {
    let [count, setCount] = useState(0);
    let [todo, setTodo] = useState([1, 2, 3, 4, 3, 5, 4]);
    const onContentChange = () => {
        count++;
        setCount(count)
    }
    const onTodoChange = () => {
        todo.push(Math.floor(Math.random() * 17) + 3);
        setTodo([...todo])
    }

    return (<>
        <div onClick={onContentChange}>改变content</div>
        <div onClick={onTodoChange}>改变todo</div>
        <div>父组件渲染次数:{count}</div>
        <Content count={count} todos={todo}></Content>
    </>)
}

export default Home;

在这里插入图片描述

六、react Hook之useRef、useImperativeHandle

useRef 是 React 提供的一个 Hook,主要用于在函数组件中存储可变值,并且在组件重新渲染时保持该值不变。useRef 返回一个可变的 ref 对象,其 current 属性可以被赋值为任何值,可搭配useImperativeHandle向父组件暴露的实例值,类似class组件种的React.createRef方式;需使用forwardRef

import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} from "react";

/******************子组件**********************/
const _Content = (props,ref) => {
    let [count, setCount] = useState(0);

    useImperativeHandle(ref,()=>({
        onCountChange: () => {
            count++;
            setCount(count);
        }
    }));

    return (<div>
        <div>页面渲染次数:{count}</div>
    </div>)
};

const Content = React.memo(forwardRef(_Content))


/******************父组件**********************/
const Home = () => {
    let ref = useRef();
    let divRef = useRef()
    const inputRef = useRef(null);

    useEffect(() => {
        console.log(ref.current); //组件挂载获取子组件暴漏出的ref示例
        console.log(divRef.current); //组件挂载获取子div元素
        inputRef.current.focus(); // 在组件挂载后使 input 元素获取焦点
    }, []);
    return (<>
        <div ref={divRef} onClick={()=>ref.current?.onCountChange()}>改变Count</div>
        <Content ref={ref}></Content>
        <input ref={inputRef} type="text"/>
    </>)
}

export default Home;

在这里插入图片描述

七、react Hook之useContext

useContext读取和订阅组件中的 context。用法:useContext(SomeContext),需要配合createContext,使用上下文 provider 包裹组件,为里面所有的组件指定一个上下文的值

import React, {useContext} from "react";

const HomeContext = React.createContext({});

/******************子组件**********************/
const _Content = () => {
    const contentValue = useContext(HomeContext);
    return (<div>{contentValue.form}</div>)
};

const Content = React.memo(_Content)


/******************父组件**********************/
const Home = () => {

    const contentValue = {
        form:'home页'
    };
    
    return (<HomeContext.Provider value={contentValue}>
        <Content/>
    </HomeContext.Provider>)
}

export default Home;
八、react Hook之useTransition

useTransition用于在渲染过渡期间对UI状态进行优化。它允许您将渲染工作分割成多个优先级较低的部分,以便浏览器可以在多个帧中完成这些工作,从而改善性能和用户体验。使用方法:const [isPending, startTransition] = useTransition();

  • isPending:是否存在待处理的 transition。
  • startTransition:函数,使用此方法将状态更新标记为 transition。
    1.不使用useTransition,代码示有四个子组件TabButton、AboutTab、ContactTab、PostsTab,其中TabButton是用来切换tab的,AboutTab、ContactTab是无耗时任务组件,PostsTab是耗时任务组件,当从AboutTab切换到PostsTab再快速切换到ContactTab,会发现PostsTab也渲染了
import React, {useEffect, useState} from "react";


/******************子组件**********************/
const _TabButton = ({children, isActive, onClick}) => {
    if (isActive) {
        return <b>{children}</b>
    }
    return (
        <button onClick={() => {
            onClick();
        }}>
            {children}
        </button>
    )
}

const TabButton = React.memo(_TabButton);

/******************子组件**********************/
const _AboutTab = () => {
    console.log("AboutTab被触发了");
    useEffect(() => {
        console.log("AboutTab被渲染");
    }, []);
    return (
        <p>Welcome to my profile!</p>
    );
}
const AboutTab = React.memo(_AboutTab);

/******************子组件**********************/
const _ContactTab = () => {
    console.log("ContactTab被触发了");
    useEffect(() => {
        console.log("ContactTab被渲染");
    }, []);
    return (
        <>
            <p>
                You can find me online here:
            </p>
            <ul>
                <li>admin@mysite.com</li>
                <li>+123456789</li>
            </ul>
        </>
    );
}
const ContactTab = React.memo(_ContactTab);

/******************子组件**********************/
function SlowPost({index}) {
    let startTime = performance.now();
    while (performance.now() - startTime < 1) {
        // 每个 item 都等待 1 毫秒以模拟极慢的代码。
    }

    return (
        <li className="item">
            Post #{index + 1}
        </li>
    );
}

const _PostsTab = () => {
    console.log("PostsTab被触发了");
    useEffect(() => {
        console.log("PostsTab被渲染");
    }, []);
    let items = [];
    for (let i = 0; i < 500; i++) {
        items.push(<SlowPost key={i} index={i}/>);
    }
    return (
        <ul className="items">
            {items}
        </ul>
    );
};

const PostsTab = React.memo(_PostsTab);

/******************父组件**********************/
const Home = () => {
    const [tab, setTab] = useState('about');

    function selectTab(nextTab) {
        setTab(nextTab);
    }

    return (
        <>
            <TabButton isActive={tab === 'about'}
                       onClick={() => selectTab('about')}>
                About
            </TabButton>
            <TabButton isActive={tab === 'posts'}
                       onClick={() => selectTab('posts')}>
                Posts (slow)
            </TabButton>
            <TabButton isActive={tab === 'contact'}
                       onClick={() => selectTab('contact')}>
                Contact
            </TabButton>
            <hr/>
            {tab === 'about' && <AboutTab/>}
            {tab === 'posts' && <PostsTab/>}
            {tab === 'contact' && <ContactTab/>}
        </>
    );
}

export default Home;

在这里插入图片描述
2.使用useTransition,当从AboutTab切换到PostsTab再快速切换到ContactTab,会发现PostsTab不会渲染了

import React, {useEffect, useState, useTransition} from "react";


/******************子组件**********************/
const _TabButton = ({children, isActive, onClick}) => {
    if (isActive) {
        return <b>{children}</b>
    }
    return (
        <button onClick={() => {
            onClick();
        }}>
            {children}
        </button>
    )
}

const TabButton = React.memo(_TabButton);

/******************子组件**********************/
const _AboutTab = () => {
    console.log("AboutTab被触发了");
    useEffect(() => {
        console.log("AboutTab被渲染");
    }, []);
    return (
        <p>Welcome to my profile!</p>
    );
}
const AboutTab = React.memo(_AboutTab);

/******************子组件**********************/
const _ContactTab = () => {
    console.log("ContactTab被触发了");
    useEffect(() => {
        console.log("ContactTab被渲染");
    }, []);
    return (
        <>
            <p>
                You can find me online here:
            </p>
            <ul>
                <li>admin@mysite.com</li>
                <li>+123456789</li>
            </ul>
        </>
    );
}
const ContactTab = React.memo(_ContactTab);

/******************子组件**********************/
function SlowPost({index}) {
    let startTime = performance.now();
    while (performance.now() - startTime < 1) {
        // 每个 item 都等待 1 毫秒以模拟极慢的代码。
    }

    return (
        <li className="item">
            Post #{index + 1}
        </li>
    );
}

const _PostsTab = () => {
    console.log("PostsTab被触发了");
    useEffect(() => {
        console.log("PostsTab被渲染");
    }, []);
    let items = [];
    for (let i = 0; i < 500; i++) {
        items.push(<SlowPost key={i} index={i}/>);
    }
    return (
        <ul className="items">
            {items}
        </ul>
    );
};

const PostsTab = React.memo(_PostsTab);

/******************父组件**********************/
const Home = () => {
    const [isPendingTab, startTransitionTab] = useTransition();
    const [tab, setTab] = useState('about');

    function selectTab(nextTab) {
        startTransitionTab(() => {
            setTab(nextTab);
        });
    }

    return (
        <>
            <TabButton isActive={tab === 'about'}
                       onClick={() => selectTab('about')}>
                About
            </TabButton>
            <TabButton isActive={tab === 'posts'}
                       onClick={() => selectTab('posts')}>
                Posts (slow)
            </TabButton>
            <TabButton isActive={tab === 'contact'}
                       onClick={() => selectTab('contact')}>
                Contact
            </TabButton>
            <hr/>
            {tab === 'about' && <AboutTab/>}
            {tab === 'posts' && <PostsTab/>}
            {tab === 'contact' && <ContactTab/>}
        </>
    );
}

export default Home;

在这里插入图片描述

九、react Hook之useDeferredValue

useDeferredValue用于延迟更新状态的值,以便在性能方面进行优化。它可以用于在某些情况下推迟对某个值的更新,以减少渲染的频率,从而提高性能。如下面代码:list组件经过大量的计算k,如果不使用useDeferredValue页面会出现明显的卡顿,使用useDeferredValue页面会变得更丝滑

import React, {useDeferredValue, useState} from "react";

/******************子组件**********************/
const _List = ({query})=>{

    console.log('List render')

    let k = 0
    for (let i = 0; i <= 200000000; i += 1) {
        k = i
    }

    return (
        <ul>
            <li>列表 {k} 文本: {query}</li>
            <li>列表 {k} 文本: {query}</li>
            <li>列表 {k} 文本: {query}</li>
            <li>列表 {k} 文本: {query}</li>
            <li>列表 {k} 文本: {query}</li>
        </ul>
    )
}

const List = React.memo(_List);

/******************父组件**********************/
const Home = () => {
    const [query, setQuery] = useState('');
    const deferredQuery = useDeferredValue(query);
    console.log("query:", query);
    console.log("deferredQuery:", deferredQuery)
    return (
        <>
            <label>
                Search albums:
                <input value={query} onChange={e => setQuery(e.target.value)}/>
            </label>
            <List query={deferredQuery}/>
        </>
    );
};

export default Home;
十、react Hook之useReducer

useReducer向组件里面添加一个 reducer,可以更好地处理复杂的状态逻辑。相比于useState,useReducer 更适合管理具有复杂状态逻辑的组件,尤其是涉及多个子值或需要在更新时执行复杂逻辑的情况。使用方法:useReducer(reducer, initValue)

import {useReducer} from "react";

function reducer(state, action) {
    if (action.type === 'incremented_age') {
        return {
            age: state.age + 1
        };
    }
    throw Error('Unknown action.');
}

const Home = () => {
    const [state, dispatch] = useReducer(reducer, { age: 42 });

    return (
        <>
            <button onClick={() => {
                dispatch({ type: 'incremented_age' })
            }}>
                Increment age
            </button>
            <p>Hello! You are {state.age}.</p>
        </>
    );
};

export default Home;
十一、react Hook之useSyncExternalStore

useSyncExternalStore 是一个可以订阅外部 store 的 React Hook。使用方法:useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)

import {useSyncExternalStore} from "react";

/******************外部store**********************/
let nextId = 0;
let todos = [{ id: nextId++, text: 'Todo #1' }];
let listeners = [];

function emitChange() {
    for (let listener of listeners) {
        listener();
    }
}

const todosStore = {
    addTodo() {
        todos = [...todos, { id: nextId++, text: 'Todo #' + nextId }]
        emitChange();
    },
    subscribe(listener) {
        listeners = [...listeners, listener];
        return () => {
            listeners = listeners.filter(l => l !== listener);
        };
    },
    getSnapshot() {
        return todos;
    }
};

/******************组件**********************/
const Home = () => {
    const todos = useSyncExternalStore(todosStore.subscribe, todosStore.getSnapshot);
    return (
        <>
            <button onClick={() => todosStore.addTodo()}>Add todo</button>
            <hr />
            <ul>
                {todos.map(todo => (
                    <li key={todo.id}>{todo.text}</li>
                ))}
            </ul>
        </>
    );
};

export default Home;

在这里插入图片描述

十二、react 组件

1.<Fragment></Fragment>、<></>:允许在不添加额外节点的情况下将子元素组合,用它包括的子元素无父节点
2.<StrictMode></StrictMode>:为组件启用严格模式
3.<Suspense fallback={}></Suspense>:处理异步组件操作的加载和错误
4.<Profiler id=“App” onRender={onRender}></Profiler>:编程式测量 React 树的渲染性能,onRender参数:id、phase、actualDuration、baseDuration、startTime、commitTime

十三、react Api

1.createContext(initValue):创建上下文,常与useContext配合使用
2.forwardRef(render):允许组件使用 ref 将 DOM 节点暴露给父组件,常与useRef、useImperativeHandle配合使用
3.lazy(load):能够让组件第一次被渲染之前延迟加载组件的代码,lazy(() => import(‘./MarkdownPreview.js’))
4.memo(SomeComponent, arePropsEqual?):允许你的组件在 props 没有改变的情况下跳过重新渲染,优化组件性能
5.startTransition():可以在不阻塞 UI 的情况下更新 state。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

局外人LZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值