Skip to content
📈0️⃣

组件中的 API - 函数组件

React 函数组件 API

React 中的函数组件主要有以下 API:

代码举例说明:

1. useState

useState:用于在函数组件中声明和管理状态。

React 中的useState是一个 Hook,用于在函数组件中添加内部状态。它接受一个初始状态作为参数,并返回一个包含两个元素的数组:当前状态和一个用于更新状态的函数。

基本语法

使用useState的基本语法如下:

javascript
import React, { useState } from 'react';

function App() {
  const [state, setState] = useState(initialState);

  // 在这里可以使用state和setState进行操作

  return (
    // 渲染组件
  );
}

在这个例子中,initialState是状态的初始值,state是当前状态,setState是一个用于更新状态的函数。当调用setState时,React 会重新渲染组件以反映新的状态。

案例: 1.1

javascript
// 案例: 1.1. React 函数组件 useState
const React = window.React;
const { useState } = React;
const { createRoot } = ReactDOM;
const App = () => {
  const [count, setCount] = useState(0);
  return (
    <p>
      useState-{count}-<button onClick={() => setCount(count + 1)}>累加</button>
    </p>
  );
};
createRoot(document.getElementById("app1")).render(<App />);

2. useEffect

useEffect:用于在函数组件中处理副作用,如异步操作、订阅事件等。

React 中的useEffect是一个 Hook,用于在函数组件中处理副作用。它接受两个参数:一个副作用函数和一个依赖数组。副作用函数是在组件渲染后执行的,而依赖数组则决定了何时执行副作用函数。

基本语法

使用useEffect的基本语法如下:

javascript
import React, { useState, useEffect } from 'react';

function App() {
  const [state, setState] = useState(initialState);
  useEffect(() => {
    // 在这里执行副作用操作
    return () => {
      // 在这里执行清理操作,例如取消订阅或清除定时器等
    };
  }, [dependency1, dependency2]); // 依赖数组,当其中的值发生变化时,副作用函数会被重新执行
  return (
    // 渲染组件
  );
}

在这个例子中,useEffect的第一个参数是一个副作用函数,它会在组件渲染后执行。第二个参数是一个依赖数组,只有当数组中的值发生变化时,副作用函数才会被重新执行。如果依赖数组为空,则副作用函数只会在组件挂载和卸载时执行一次。

案例: 1.2

javascript
// 案例: 1.2. React 函数组件 useEffect
const { useState, useEffect } = React;
const { createRoot } = ReactDOM;
const App = () => {
  const getTime = () => new Date().toLocaleTimeString();
  const [time, setTime] = useState(getTime());
  let timerId = null;
  const updateTime = () => {
    timerId = setInterval(() => setTime(getTime()), 1000);
  };
  useEffect(() => {
    // 回调函数的作用同 componentDidMount
    document.title = time;
    updateTime();
    return () => clearInterval(timerId); // return 作用同 componentWillUnmount
  }, [time]); // 第二参数作用是监听 state, 传空数组不监听数据
  return <p>useEffect-页面标题-计时器-->{time}</p>;
};
createRoot(document.getElementById("app2")).render(<App />);

3. useContext

useContext:用于在函数组件中使用 Context。

React 中的useContext是一个 Hook,用于在函数组件中访问 React 的上下文。它接受一个上下文对象作为参数,并返回该上下文的值。

基本语法

使用useContext的基本语法如下:

javascript
import React, { useContext } from 'react';
const MyContext = React.createContext(initialValue);
function App() {
  const contextValue = useContext(MyContext);
  // 在这里可以使用contextValue进行操作
  return (
    // 渲染组件
  );
}

在这个例子中,MyContext是一个通过React.createContext创建的上下文对象,initialValue是上下文的初始值。useContext接受MyContext作为参数,并返回当前上下文的值,即contextValue。当上下文的值发生变化时,useContext会重新渲染组件以反映新值。

案例: 1.3

MyContext = createContext() 类似于 vue 中的 provide/inject

javascript
// 案例: 1.3. React 函数组件 useContext
const { createRoot } = ReactDOM;
const { createContext, useContext, useState, useEffect } = React;
// 创建 MyProvider 提供者组件, 用于提供数据并传子子组件
const MyContext = createContext();
const MyProvider = ({ children, value }) => (
  <MyContext.Provider value={value}>{children}</MyContext.Provider>
);
// 创建 Child 消费者组件, 用于接收数据
const Child1 = () => {
  const value = useContext(MyContext);
  return <span>{value}</span>;
};
const Child2 = () => {
  const value = useContext(MyContext);
  return <span>{value}</span>;
};
// 将 Child1 包装在 MyProvider 组件中, 当 value 变化时, 所有包装的 Child 都会更新
const App = () => {
  const [value, setValue] = useState(Math.random());
  let timerId = null;
  const update = () => {
    timerId = setInterval(() => setValue(Math.random()), 2000);
    return () => clearInterval(timerId);
  };
  useEffect(() => update(), [value]);
  return (
    <div>
      <MyProvider value={value}>
        useContext-value-
        <Child1 />-<Child2 />
      </MyProvider>
    </div>
  );
};
createRoot(document.getElementById("app3")).render(<App />);

4. useReducer

useReducer:用于在函数组件中管理复杂的状态逻辑。

React 中的useReducer是一个 Hook,用于在函数组件中处理复杂的状态逻辑。它接受两个参数:一个 reducer 函数和一个初始状态。reducer 函数是一个纯函数,用于根据当前状态和传入的 action 来生成新的状态。

基本语法

使用useReducer的基本语法如下:

javascript
import React, { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

  // 在这里可以使用state和dispatch进行操作

  return (
    // 渲染组件
  );
}

在这个例子中,initialState是状态的初始值,reducer是一个纯函数,用于根据当前状态和传入的 action 来生成新的状态。useReducer返回一个包含两个元素的数组:当前状态和一个用于派发 action 的函数。当调用dispatch时,React 会调用reducer函数并传入当前状态和传入的 action,然后根据返回的新状态更新组件。

案例: 1.4

作用类似 Vuex 和 Pinia

javascript
// 案例: 1.4. React 函数组件 useReducer
const { createRoot } = ReactDOM;
const { useReducer } = React;
const App = () => {
  const reducer = (state, action) => {
    console.log("useReducer", state, action);
    switch (action.type) {
      case "increment":
        return state + 1;
      case "decrement":
        return state - 1;
      default:
        return state;
    }
  };
  let initialState = 0;
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <p>
      useReducer-{state}-
      <button onClick={() => dispatch({ type: "increment" })}>加</button>
      <button onClick={() => dispatch({ type: "decrement" })}>减</button>
    </p>
  );
};
createRoot(document.getElementById("app4")).render(<App />);

5. useCallback

useCallback:用于在函数组件中缓存函数,避免不必要的重新渲染。

React 中的useCallback是一个 Hook,用于在函数组件中缓存函数的引用。它接受两个参数:需要缓存的函数和依赖项数组。当依赖项数组中的某个值发生变化时,useCallback会返回一个新的函数引用;否则,它会返回之前的函数引用。

基本语法

使用useCallback的基本语法如下:

javascript
import React, { useState, useCallback } from "react";

function ChildComponent({ onClick }) {
  return <button onClick={onClick}>点击我</button>;
}

function ParentComponent() {
  const [count, setCount] = useState(0);

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

  return (
    <div>
      <h1>计数器: {count}</h1>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

export default ParentComponent;

在这个例子中,ParentComponent有一个状态count和一个处理函数handleClick。我们将handleClick传递给子组件ChildComponent作为onClick属性。通过使用useCallback,我们确保只有在count发生变化时,handleClick才会更新。这样可以避免不必要的子组件重新渲染,提高性能。

案例: 1.5

javascript
// 案例: 1.5. React 函数组件 useCallback
const { createRoot } = ReactDOM;
const { useState, useCallback } = React;
const Child = ({ onClick }) => {
  return <button onClick={onClick}>useCallback-点击</button>;
};
const App = () => {
  const [count, setCount] = useState(0);
  const onClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);
  return (
    <p>
      <span>useCallback-计数器-{count}-</span>
      <Child onClick={onClick} />
    </p>
  );
};
createRoot(document.getElementById("app5")).render(<App />);

6. useMemo

useMemo:用于在函数组件中缓存计算结果,避免不必要的重新计算。

useMemo 是 React 提供的一个 Hook,它用于优化那些因为依赖值的小变化而导致的不必要的重新计算。这个 Hook 特别适合于那些执行成本较高的计算,例如计算大量数据的函数或者请求,我们不希望这些操作在依赖值每次微小变化时都执行一次。

基本语法

useMemo 接受两个参数:一个“记忆”的函数和一个依赖项数组。只有当依赖项数组中的某个值发生变化时,useMemo 才会调用该函数并缓存其结果。如果依赖项没有变化,它会返回上一次调用的结果,而不会再次调用该函数。

以下是 useMemo 的基本使用示例:

javascript
import React, { useState, useMemo } from "react";

function ExpensiveCalculation({ inputValue }) {
  // 假设这是一个高成本的计算函数
  return inputValue.length * 2;
}

function App() {
  const [inputValue, setInputValue] = useState("");

  const expensiveResult = useMemo(() => {
    return ExpensiveCalculation({ inputValue });
  }, [inputValue]); // 仅当 inputValue 改变时重新计算

  return (
    <div>
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      {/* 使用计算结果 */}
      <p>计算结果: {expensiveResult}</p>
    </div>
  );
}

export default App;

在这个例子中,ExpensiveCalculation 是一个执行成本较高的函数,它依赖于 inputValue。通过使用 useMemo,我们可以确保只有在 inputValue 改变时,才会重新计算 expensiveResult。这有助于避免不必要的性能开销。

案例: 1.6

类似 Vue 中的 computed

javascript
// 案例: 1.6. React 函数组件 useMemo
const { createRoot } = ReactDOM;
const { useState, useMemo } = React;
const CalcFoo = (v) => v.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); // 计算耗时操作
const App = () => {
  const [count, setCount] = useState(10000);
  const resultValue = useMemo(() => CalcFoo(count), [count]); // 依赖 count 变化
  return (
    <p>
      <span>useMemo-千分符-{resultValue}</span>-
      <input value={count} onChange={(e) => setCount(e.target.value)} />
    </p>
  );
};
createRoot(document.getElementById("app6")).render(<App />);

7. useRef

useRef:用于在函数组件中创建和访问 ref。

基本语法

useRef 是 React 提供的一个 Hook,用于在函数组件中创建和访问可变的引用。它返回一个可变的 ref 对象,该对象具有一个 current 属性,可以用来存储和访问任何类型的值。

以下是一个简单的示例:

javascript
import React, { useRef } from "react";

function MyComponent() {
  const myRef = useRef(null);

  return (
    <div>
      <input ref={myRef} />
      <button onClick={() => console.log(myRef.current)}>
        Log input value
      </button>
    </div>
  );
}

在这个例子中,我们使用 useRef 创建了一个名为 myRef 的引用,并将其分配给了一个输入框。然后,我们在按钮的点击事件处理程序中使用 console.log 打印了输入框的值。由于 myRef 是一个可变的引用,因此我们可以在组件的生命周期内随时更新其值。

案例: 1.7

类似 Vue 中的 ref

javascript
// 案例: 1.7. React 函数组件 useRef
const { createRoot } = ReactDOM;
const { useRef } = React;
const App = () => {
  const myRef = useRef(null);
  return (
    <p>
      useRef-
      <input ref={myRef} />-<button onClick={() => alert(myRef.current)}>alert(input)</button>
    </p>
  );
};
createRoot(document.getElementById("app7")).render(<App />);

8. forwardRef

forwardRef:用于在父组件中访问子组件的 ref。

基本语法

forwardRef 是 React 提供的一个高阶组件(HOC),用于在父组件中访问子组件的 ref。它允许你将 ref 转发给子组件,这样你就可以在父组件中直接操作子组件的实例。

以下是一个简单的示例:

javascript
import React, { forwardRef } from "react";

const ChildComponent = forwardRef((props, ref) => {
  return <input ref={ref} />;
});

function ParentComponent() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <ChildComponent ref={inputRef} />
      <button onClick={handleClick}>Focus input</button>
    </div>
  );
}

在这个例子中,我们使用 forwardRef 创建了一个名为 ChildComponent 的子组件。然后,我们在 ParentComponent 中使用 useRef 创建了一个名为 inputRef 的引用,并将其分配给 ChildComponent。当点击按钮时,我们调用 inputRef.current.focus() 方法来聚焦输入框。

案例: 1.8

javascript
// 案例: 1.8. React 函数组件 forwardRef
const { createRoot } = ReactDOM;
const { forwardRef } = React;
// 高阶函数包装子组件, 用于 ref 传参
const ChildInput = forwardRef((props, ref) => (
  <input ref={ref} style={{ height: "20px" }} />
));
const App = () => {
  const inputRef = useRef(null);
  const onFocus = () => inputRef.current.focus();
  return (
    <p>
      forwardRef-
      <ChildInput ref={inputRef} />-<button onClick={onFocus}>聚焦输入框</button>
    </p>
  );
};
createRoot(document.getElementById("app8")).render(<App />);

9. useImperativeHandle

useImperativeHandle:用于在函数组件中暴露自定义的 ref 属性。

基本语法

useImperativeHandle 是 React 提供的一个 Hook,用于在父组件中操作子组件的实例。它接受两个参数:一个 ref 和一个函数,该函数返回一个对象,该对象包含要暴露给父组件的方法和属性。

以下是一个简单的示例:

javascript
import React, { useRef, forwardRef, useImperativeHandle } from "react";
const ChildComponent = forwardRef((props, ref) => {
  const inputRef = useRef(null);
  useImperativeHandle(ref, () => ({
    focusInput: () => inputRef.current.focus();
  }));
  return <input ref={inputRef} />;
});
const ParentComponent = () => {
  const childRef = useRef(null);
  const handleClick = () => childRef.current.focusInput();
  return (
    <p>
      <ChildComponent ref={childRef} />
      <button onClick={handleClick}>Focus input</button>
    </p>
  );
}

在这个例子中,我们使用 forwardRefChildComponent 的 ref 传递给它。然后,我们在 ChildComponent 中使用 useImperativeHandle 创建一个名为 focusInput 的方法,该方法将焦点设置到输入框上。最后,我们在 ParentComponent 中使用 useRef 创建了一个名为 childRef 的引用,并将其分配给 ChildComponent。当点击按钮时,我们调用 childRef.current.focusInput() 方法来聚焦输入框。

案例: 1.9

javascript
// 案例: 1.9. React 函数组件 useImperativeHandle
const { createRoot } = ReactDOM;
const { forwardRef, useImperativeHandle } = React;
// 高阶函数 forwardRef 包装子组件, 用于 ref 传参
const ChildInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);
  // useImperativeHandle Hook 用于暴露子组件的实例方法
  useImperativeHandle(ref, () => ({
    ...inputRef,
    focus: () => {
      console.log("暴露了重新的 focus 方法");
      inputRef.current.focus();
      inputRef.current.style.color = "red";
    },
  }));
  return <input ref={inputRef} />;
});
const App = () => {
  const childRef = useRef(null);
  const handleClick = () => childRef.current.focus();
  return (
    <p>
      useImperativeHandle-
      <ChildInput ref={childRef} />-<button onClick={handleClick}>聚焦输入框</button>
    </p>
  );
};
createRoot(document.getElementById("app9")).render(<App />);

10. useLayoutEffect

useLayoutEffect:与 useEffect 类似,但执行时机不同,useLayoutEffect 会在 DOM 更新后同步执行。

基本语法

useLayoutEffect 是 React 提供的一个 Hook,用于在函数组件中执行副作用操作。与 useEffect 不同,useLayoutEffect 的副作用操作会在浏览器完成布局之后同步执行,这可以确保在浏览器绘制之前完成副作用操作。

以下是一个简单的示例:

javascript
// 案例: 1.10. React 函数组件 useLayoutEffect
const { createRoot } = ReactDOM;
const { useLayoutEffect } = React;
const App = () => {
  useLayoutEffect(
    () => console.log("This will run after the browser has completed layout"),
    []
  );
  return <p>useLayoutEffect-Hello World</p>;
};
createRoot(document.getElementById("app10")).render(<App />);

在这个例子中,我们使用 useLayoutEffect 创建了一个副作用操作,该操作会在浏览器完成布局之后同步执行。由于 useLayoutEffect 的副作用操作会在浏览器绘制之前完成,因此我们可以确保在浏览器绘制之前完成副作用操作。

11. useDebugValue

useDebugValue:用于在开发者工具中显示自定义的调试信息。

基本语法

useDebugValue 是 React 提供的一个 Hook,用于在开发模式下为自定义 Hook 添加调试信息。它接受一个参数,即要显示的调试信息。

以下是一个简单的示例:

javascript
// 案例: 1.11. React 函数组件 useDebugValue
const { createRoot } = ReactDOM;
const { useState, useDebugValue } = React;
const useCounter = () => {
  const [count, setCount] = useState(0);
  console.log(
    "在 CDN 模式下 useDebugValue 不会起作用, 只有在开发模式下才会启用"
  );
  useDebugValue("useCounter", count);
  return { count, setCount };
};
const App = () => {
  const { count, setCount } = useCounter();
  return (
    <p>
      useDebugValue-count-{count}-
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </p>
  );
};
createRoot(document.getElementById("app11")).render(<App />);

在这个例子中,我们创建了一个名为 useCounter 的自定义 Hook,该 Hook 使用 useState 管理计数器的状态。然后,我们使用 useDebugValue 为该 Hook 添加了调试信息,以便在开发模式下显示当前计数器的值。最后,我们在 MyComponent 中使用 useCounter 来获取计数器的状态和更新方法。

代码与演示

1. 全部代码

点击查看代码
html
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>test-react-api-函数组件</title>
    <!-- <script src="https://cdn.staticfile.org/react/18.0.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/18.0.0/umd/react-dom.development.js"></script>
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> -->
    <script src="./react.js"></script>
    <script src="./react-dom.js"></script>
    <script src="./babel.js"></script>
  </head>

  <body>
    <div id="app1"></div>
    <div id="app2"></div>
    <div id="app3"></div>
    <div id="app4"></div>
    <div id="app5"></div>
    <div id="app6"></div>
    <div id="app7"></div>
    <div id="app8"></div>
    <div id="app9"></div>
    <div id="app10"></div>
    <div id="app11"></div>

    <script type="text/babel">
      {
        // 案例: 1.1. React 函数组件 useState
        const React = window.React;
        const { useState } = React;
        const { createRoot } = ReactDOM;
        const App = () => {
          const [count, setCount] = useState(0);
          return (
            <p>
              useState-{count}-
              <button onClick={() => setCount(count + 1)}>累加</button>
            </p>
          );
        };
        createRoot(document.getElementById("app1")).render(<App />);
      }
    </script>

    <script type="text/babel">
      {
        // 案例: 1.2. React 函数组件 useEffect
        const { useState, useEffect } = React;
        const { createRoot } = ReactDOM;
        const App = () => {
          const getTime = () => new Date().toLocaleTimeString();
          const [time, setTime] = useState(getTime());
          let timerId = null;
          const updateTime = () => {
            timerId = setInterval(() => setTime(getTime()), 1000);
          };
          useEffect(() => {
            // 回调函数的作用同 componentDidMount
            document.title = time;
            updateTime();
            return () => clearInterval(timerId); // return 作用同 componentWillUnmount
          }, [time]); // 第二参数作用是监听 state, 传空数组不监听数据
          return <p>useEffect-页面标题-计时器-->{time}</p>;
        };
        createRoot(document.getElementById("app2")).render(<App />);
      }
    </script>

    <script type="text/babel">
      {
        // 案例: 1.3. React 函数组件 useContext
        const { createRoot } = ReactDOM;
        const { createContext, useContext, useState, useEffect } = React;
        // 创建 MyProvider 提供者组件, 用于提供数据并传子子组件
        const MyContext = createContext();
        const MyProvider = ({ children, value }) => (
          <MyContext.Provider value={value}>{children}</MyContext.Provider>
        );
        // 创建 Child 消费者组件, 用于接收数据
        const Child1 = () => {
          const value = useContext(MyContext);
          return <span>{value}</span>;
        };
        const Child2 = () => {
          const value = useContext(MyContext);
          return <span>{value}</span>;
        };
        // 将 Child1 包装在 MyProvider 组件中, 当 value 变化时, 所有包装的 Child 都会更新
        const App = () => {
          const [value, setValue] = useState(Math.random());
          let timerId = null;
          const update = () => {
            timerId = setInterval(() => setValue(Math.random()), 2000);
            return () => clearInterval(timerId);
          };
          useEffect(() => update(), [value]);
          return (
            <div>
              <MyProvider value={value}>
                useContext-value-
                <Child1 />-<Child2 />
              </MyProvider>
            </div>
          );
        };
        createRoot(document.getElementById("app3")).render(<App />);
      }
    </script>

    <script type="text/babel">
      {
        // 案例: 1.4. React 函数组件 useReducer
        const { createRoot } = ReactDOM;
        const { useReducer } = React;
        const App = () => {
          const reducer = (state, action) => {
            console.log("useReducer", state, action);
            switch (action.type) {
              case "increment":
                return state + 1;
              case "decrement":
                return state - 1;
              default:
                return state;
            }
          };
          let initialState = 0;
          const [state, dispatch] = useReducer(reducer, initialState);
          return (
            <p>
              useReducer-{state}-
              <button onClick={() => dispatch({ type: "increment" })}>

              </button>
              <button onClick={() => dispatch({ type: "decrement" })}>减</button>
            </p>
          );
        };
        createRoot(document.getElementById("app4")).render(<App />);
      }
    </script>

    <script type="text/babel">
      {
        // 案例: 1.5. React 函数组件 useCallback
        const { createRoot } = ReactDOM;
        const { useState, useCallback } = React;
        const Child = ({ onClick }) => {
          return <button onClick={onClick}>useCallback-点击</button>;
        };
        const App = () => {
          const [count, setCount] = useState(0);
          const onClick = useCallback(() => {
            setCount(count + 1);
          }, [count]);
          return (
            <p>
              <span>useCallback-计数器-{count}-</span>
              <Child onClick={onClick} />
            </p>
          );
        };
        createRoot(document.getElementById("app5")).render(<App />);
      }
    </script>

    <script type="text/babel">
      {
        // 案例: 1.6. React 函数组件 useMemo
        const { createRoot } = ReactDOM;
        const { useState, useMemo } = React;
        const CalcFoo = (v) =>
          v.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); // 计算耗时操作
        const App = () => {
          const [count, setCount] = useState(10000);
          const resultValue = useMemo(() => CalcFoo(count), [count]); // 依赖 count 变化
          return (
            <p>
              <span>useMemo-千分符-{resultValue}</span>-
              <input value={count} onChange={(e) => setCount(e.target.value)} />
            </p>
          );
        };
        createRoot(document.getElementById("app6")).render(<App />);
      }
    </script>

    <script type="text/babel">
      {
        // 案例: 1.7. React 函数组件 useRef
        const { createRoot } = ReactDOM;
        const { useRef } = React;
        const App = () => {
          const myRef = useRef(null);
          return (
            <p>
              useRef-
              <input ref={myRef} />-<button onClick={() => alert(myRef.current)}>alert(input)</button>
            </p>
          );
        };
        createRoot(document.getElementById("app7")).render(<App />);
      }
    </script>

    <script type="text/babel">
      {
        // 案例: 1.8. React 函数组件 forwardRef
        const { createRoot } = ReactDOM;
        const { forwardRef } = React;
        // 高阶函数包装子组件, 用于 ref 传参
        const ChildInput = forwardRef((props, ref) => (
          <input ref={ref} style={{ height: "20px" }} />
        ));
        const App = () => {
          const inputRef = useRef(null);
          const onFocus = () => inputRef.current.focus();
          return (
            <p>
              forwardRef-
              <ChildInput ref={inputRef} />-<button onClick={onFocus}>聚焦输入框</button>
            </p>
          );
        };
        createRoot(document.getElementById("app8")).render(<App />);
      }
    </script>

    <script type="text/babel">
      (function () {
        // 案例: 1.9. React 函数组件 useImperativeHandle
        const { createRoot } = ReactDOM;
        const { forwardRef, useImperativeHandle } = React;
        // 高阶函数 forwardRef 包装子组件, 用于 ref 传参
        const ChildInput = forwardRef((props, ref) => {
          const inputRef = useRef(null);
          // useImperativeHandle Hook 用于暴露子组件的实例方法
          useImperativeHandle(ref, () => ({
            ...inputRef,
            focus: () => {
              console.log("暴露了重新的 focus 方法");
              inputRef.current.focus();
              inputRef.current.style.color = "red";
            },
          }));
          return <input ref={inputRef} />;
        });
        const App = () => {
          const childRef = useRef(null);
          const handleClick = () => childRef.current.focus();
          return (
            <p>
              useImperativeHandle-
              <ChildInput ref={childRef} />-<button onClick={handleClick}>聚焦输入框</button>
            </p>
          );
        };
        createRoot(document.getElementById("app9")).render(<App />);
      })();
    </script>

    <script type="text/babel">
      {
        // 案例: 1.10. React 函数组件 useLayoutEffect
        const { createRoot } = ReactDOM;
        const { useLayoutEffect } = React;
        const App = () => {
          useLayoutEffect(
            () =>
              console.log(
                "This will run after the browser has completed layout"
              ),
            []
          );
          return <p>useLayoutEffect-Hello World</p>;
        };
        createRoot(document.getElementById("app10")).render(<App />);
      }
    </script>

    <script type="text/babel">
      {
        // 案例: 1.11. React 函数组件 useDebugValue
        const { createRoot } = ReactDOM;
        const { useState, useDebugValue } = React;
        const useCounter = () => {
          const [count, setCount] = useState(0);
          console.log(
            "在 CDN 模式下 useDebugValue 不会起作用, 只有在开发模式下才会启用"
          );
          useDebugValue("useCounter", count);
          return { count, setCount };
        };
        const App = () => {
          const { count, setCount } = useCounter();
          return (
            <p>
              useDebugValue-count-{count}-
              <button onClick={() => setCount(count + 1)}>Increment</button>
            </p>
          );
        };
        createRoot(document.getElementById("app11")).render(<App />);
      }
    </script>
  </body>
</html>

2. 案例演示




test-react-api-func.html 资源加载中...