undefined
前言
React的函数式(Functional Component)组件学习笔记
定义组件
- 组件名首字母大写
return可以返回的数据类型,与类组件相同
1 2 3 4 5 6 7
| const Component = function (props) { return ( <></> ); }
export default Component;
|
1 2 3 4 5 6 7
| const Component = function (props) { return ( <> <div className=""></div> </> ); }
|
1 2 3 4 5 6 7 8 9
| const Component = function (props) { return ( <> <label htmlFor="input"> <input id="input" type="text" /> </label> </> ); }
|
定义纯组件
1 2 3 4 5 6 7 8 9
| import { memo } from "react";
const Component = memo(function (props) { return ( <></> ); });
export default Component;
|
父子组件跨多级传递数据
祖先组件传递数据给子孙组件
创建上下文对象
src/AppContext.jsx1 2 3
| import React from "react";
const AppContext = React.createContext();
|
定义默认值
src/AppContext.jsx1 2 3
| import React from "react";
const AppContext = React.createContext({key: "default"});
|
组件组件向子孙组件传递数据
- 使用上下文对象的
Provider组件包裹子组件
- 在上下文对象的
Provider组件定义value属性,通过value属性向子孙传递数据
src/GrandFather.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import AppContext from "./AppContext"; import Father from "./Father";
function GrandFather() { return ( <> <AppContext.Provider value={ {key: "value"} }> <Father /> </AppContext.Provider> </> ); }
export default GrandFather;
|
src/Father.jsx1 2 3 4 5 6 7 8 9 10 11
| import Son from "./Son";
function Father() { return ( <> <Son /> </> ); }
export default Father;
|
子孙组件获取祖先组件传递的数据
通过向Customer中传递回调函数获取数据
src/Son.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import AppContext from "./AppContext";
function Son() { return ( <> <AppContext.Consumer> { (context) => { return context.key; } } </AppContext.Consumer> </> ); }
export default Son;
|
src/Son.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import AppContext from "./AppContext";
function Son() { return ( <> <App1Context.Consumer> { (context) => { return context.key; } } </App1Context.Consumer> <App2Context.Consumer> { (context) => { return context.key; } } </App2Context.Consumer> </> ); }
export default Son;
|
Hooks
组件的状态
定义组件的状态
- 如果没有定义状态默认值,则默认为
undefined
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { useState } from "react";
const Component = function (props) { const [ key, setKey ] = useState();
return ( <> <div>{ key }</div> </> ); }
export default Component;
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { useState } from "react";
const Component = function (props) { const [ key, setKey ] = useState("default");
return ( <> <div>{ key }</div> </> ); }
export default Component;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { useState } from "react";
const Component = function (props) { const [ key, setKey ] = useState(function () { return "default"; });
return ( <> <div>{ key }</div> </> ); }
export default Component;
|
修改组件的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { useState } from "react";
const Component = function (props) { const [ key, setKey ] = useState();
function fn() { setKey("value"); }
return ( <> <div onClick={ fn }>{ key }</div> </> ); }
export default Component;
|
组件的副作用
useEffect()中传递的函数会在组件每次渲染完成之后(首次渲染之后或重新渲染之后)立即执行一次
useEffect()中传递的函数的返回值是一个函数,这个返回的函数会在组件重新渲染之前或卸载之后立即执行一次
useEffect()可以在函数式组件中定义多个,会按照定义时的顺序依次执行
useEffect()中传递的数组表示回调函数在哪些依赖项改变时才会重新执行
- 如果数组为空,则表示回调函数只会在首次渲染执行一次
- 如果没有传递数组,则表示回调函数会在组件每次渲染完成之后都重新执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { useEffect } from "react";
const Component = function (props) { useEffect(function () {
... return function () { ... } }, []);
return ( <></> ); }
export default Component;
|
组件的布局副作用
useLayoutEffect()与useEffect()参数相同,但useEffect()是页面渲染之后异步执行useEffect()传入的函数,而useLayoutEffect()是页面渲染之前同步执行useLayoutEffect()传入的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { useLayoutEffect } from "react";
const Component = function (props) { useLayoutEffect(function () {
... return function () { ... } }, []);
return ( <></> ); }
export default Component;
|
上下文对象
创建上下文对象
src/AppContext.jsx1 2 3 4 5
| import React from "react";
const AppContext = React.createContext();
export default AppContext;
|
src/AppContext.jsx1 2 3 4 5
| import React from "react";
const AppContext = React.createContext({key: "default"});
export default AppContext;
|
祖先组件向子孙组件传递数据
- 使用上下文对象的
Provider组件包裹子组件
- 在上下文对象的
Provider组件定义value属性,通过value属性向子孙传递数据
src/GrandFather.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import React from "react"; import AppContext from "./AppContext"; import Father from "./Father";
class GrandFather extends React.Component { render() { return ( <> <AppContext.Provider value={ {key: "value"} }> <Father /> </AppContext.Provider> </> ); } }
export default GrandFather;
|
src/Father.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import React from "react"; import Son from "./Son";
class Father extends React.Component { render() { return ( <> <Son /> </> ); } }
export default Father;
|
子孙组件获取祖先组件传递的数据
- 每当上下文对象中的数据发生改变,函数式组件都会立即重新渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { useContext } from "react"; import AppContext from "./AppContext";
const Component = function (props) { const appContext = useContext(AppContext);
return ( <> <div>{ appContext.key }</div> </> ); }
export default Component;
|
优化函数
useEffect()中传递一个函数,这个函数被useEffect()处理后返回一个memoized(记忆的)函数作为useEffect()的结果,这个结果就是被优化后的函数,这个被优化后的函数在依赖不变的情况下,多次定义的时候,返回的是相同的函数(引用)
useEffect()中传递的数组表示在哪些依赖项改变时才会返回新的函数
- 如果数组为空,则表示只会返回相同的函数
- 如果没有传递数组,则表示只会返回新的函数
在将函数传递给子组件时,使用被useCallback()优化后的函数传递给子组件,可以避免子组件被意外的重新渲染,实现性能优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { useCallback } from "react";
const Component = function (props) { const fn = function () { ... } const memoizedFn = useCallback(fn, []);
return ( <></> ); }
export default Component;
|
优化对象
useMemo()中传递一个有返回对象的函数,这个返回的对象被useMemo()处理后最终返回一个memoized(记忆的)对象作为useMemo()的结果,这个结果就是被优化后的对象,这个被优化后的对象在依赖不变的情况下,多次定义的时候,返回的是相同的对象(引用)
useMemo()中传递的数组表示在哪些依赖项改变时才会返回新的对象
- 如果数组为空,则表示只会返回相同的对象
- 如果没有传递数组,则表示只会返回新的对象
在将对象传递给子组件时,使用被useMemo()优化后的对象传递给子组件,可以避免子组件被意外的重新渲染,实现性能优化
1 2 3 4 5 6 7 8 9 10 11 12
| import { useMemo } from "react";
const Component = function (props) { const obj = {} const memoizedObj = useMemo(() => obj, []);
return ( <></> ); }
export default Component;
|
不变的引用对象
通过Ref获取DOM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { useRef } from "react";
function Component() { const divRef = useRef();
function fn() { const dom = divRef.current; }
return ( <> <div ref={ divRef }></div> </> ); }
export default Component;
|
通过Ref获取子组件的DOM
src/components/Son.jsx1 2 3 4 5 6 7 8 9 10 11
| import { forwardRef } from "react";
const Son = forwardRef(function (props, ref) { return ( <> <div ref={ ref }></div> </> ); });
export default Son;
|
src/components/Father.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { useRef } from "react"; import Son from "./Son";
const Father = function () { const divRef = useRef();
function fn() { const dom = divRef.current; }
return ( <> <Son ref={ divRef } /> </> ); }
export default Father;
|
在子组件中重写父组件的引用
src/components/Son.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { forwardRef, useRef, useImperativeHandler } from "react";
const Son = forwardRef(function (props, ref) { const divRef = useRef();
useImperativeHandler(ref, () => ({ fn: () => { const dom = divRef.current; } }));
return ( <> <div ref={ divRef }></div> </> ); });
export default Son;
|
- 父组件通过获取子组件的引用只能调用子组件暴露的特定功能
src/components/Father.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { useRef } from "react"; import Son from "./Son";
const Father = function () { const divRef = useRef();
function fn() { divRef.current.fn(); }
return ( <> <Son ref={ divRef } /> </> ); }
export default Father;
|
通过Ref定义一个不会改变的对象
- 通过Ref定义一个不会改变的对象,并绑定一个值,避免闭包陷阱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { useCallback, useRef } from "react";
function Component() { const [key, setKey] = useState(0); const keyRef = useRef(); function fn() { setKey(keyRef.current + 1); } const memoizedFn = useCallback(fn, []);
return ( <></> ); }
export default Component;
|
在同构应用中生成相同编号
- 在同构应用中生成不论是服务端渲染还是客户端渲染都相同的编号
1 2 3 4 5 6 7 8 9 10 11
| import { useId } from "react";
function Component() { const id = useId(); return ( <></> ); }
export default Component;
|
降低函数执行的优先级
startTransition()中传入的函数优先级低于页面渲染
- 在
startTransition()中传入的函数没有执行完成时,isPending结果为true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { useTransition } from "react";
function Component() { const [isPending, startTransition] = useTransition(); function fn() { ... } startTransition(fn);
return ( <> { isPending && <div>Loading...</div> } </> ); }
export default Component;
|
暂缓更新数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { useDeferredValue, useState } from "react";
function Component() { const [key, setKey] = useState(); const deferredKey = useDeferredValue(key);
return ( <> { deferredKey } </> ); }
export default Component;
|
自定义Hook
1 2 3
| function useFn() { ... }
|
完成