useState

React 中的 useState 详解

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - useState</title>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useState } = React;

      function Counter() {
        const [count, setCount] = useState(0);
        const [name, setName] = useState("React");

        return (
          <div>
            <h2>Hook 入门:useState</h2>
            <p>当前计数:{count}</p>
            <button onClick={() => setCount(count + 1)}>点击 +1</button>
            <button onClick={() => setCount(count - 1)}>点击 -1</button>

            <div style={{ marginTop: 20 }}>
              <p>当前名称:{name}</p>
              <input
                type="text"
                value={name}
                onChange={(event) => setName(event.target.value)}
              />
            </div>
          </div>
        );
      }

      ReactDOM.render(<Counter />, document.getElementById("example"));
    </script>
  </body>
</html>

useEffect

React 中的 useEffect 详解

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - useEffect</title>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useState, useEffect, useRef } = React;

      function Timer() {
        const [time, setTime] = useState(new Date().toLocaleTimeString());
        const inputRef = useRef(null);

        useEffect(() => {
          const timer = setInterval(() => {
            setTime(new Date().toLocaleTimeString());
          }, 1000);

          return () => {
            clearInterval(timer);
          };
        }, []);

        useEffect(() => {
          document.title = "当前时间:" + time;
        }, [time]);

        return (
          <div>
            <h2>Hook 入门:useEffect + useRef</h2>
            <p>当前时间:{time}</p>

            <input ref={inputRef} defaultValue="Hello Hook" />
            <button onClick={() => inputRef.current.focus()}>聚焦输入框</button>
          </div>
        );
      }

      ReactDOM.render(<Timer />, document.getElementById("example"));
    </script>
  </body>
</html>

useRef

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - useRef</title>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useRef, useState, useEffect } = React;

      function InputFocusDemo() {
        const inputRef = useRef(null);
        const [count, setCount] = useState(0);

        useEffect(() => {
          console.log("inputRef.current:", inputRef.current);
        }, [count]);

        return (
          <div>
            <h2>Hook 进阶:useRef</h2>
            <input ref={inputRef} type="text" defaultValue="Hello React" />
            <button onClick={() => inputRef.current && inputRef.current.focus()}>
              聚焦输入框
            </button>

            <p>点击次数:{count}</p>
            <button onClick={() => setCount(count + 1)}>更新计数</button>
          </div>
        );
      }

      ReactDOM.render(<InputFocusDemo />, document.getElementById("example"));
    </script>
  </body>
</html>

useCallback

React 中的 useCallback 详解

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - useCallback</title>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useState, useCallback, memo } = React;

      const Child = memo(function Child({ onClick, count }) {
        console.log("Child render");
        return <button onClick={onClick}>子组件点击:{count}</button>;
      });

      function Parent() {
        const [count, setCount] = useState(0);
        const [other, setOther] = useState(0);

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

        return (
          <div>
            <h2>Hook 进阶:useCallback</h2>
            <p>父组件其他状态:{other}</p>
            <button onClick={() => setOther(other + 1)}>更新其他状态</button>
            <Child onClick={handleClick} count={count} />
          </div>
        );
      }

      ReactDOM.render(<Parent />, document.getElementById("example"));
    </script>
  </body>
</html>

customHook

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - Custom Hook</title>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useState, useEffect } = React;

      function useWindowSize() {
        const [size, setSize] = useState({
          width: window.innerWidth,
          height: window.innerHeight,
        });

        useEffect(() => {
          const handleResize = () => {
            setSize({
              width: window.innerWidth,
              height: window.innerHeight,
            });
          };

          window.addEventListener("resize", handleResize);
          return () => window.removeEventListener("resize", handleResize);
        }, []);

        return size;
      }

      function WindowSizeDemo() {
        const size = useWindowSize();

        return (
          <div>
            <h2>Hook 进阶:自定义 Hook</h2>
            <p>窗口宽度:{size.width}</p>
            <p>窗口高度:{size.height}</p>
          </div>
        );
      }

      ReactDOM.render(<WindowSizeDemo />, document.getElementById("example"));
    </script>
  </body>
</html>

form-demo

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - Form Demo</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        padding: 30px;
      }
      .card {
        width: 360px;
        padding: 20px;
        border: 1px solid #ddd;
        border-radius: 8px;
      }
      input, button {
        margin-top: 10px;
        width: 100%;
        box-sizing: border-box;
        padding: 8px;
      }
      button {
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useState } = React;

      function UserForm() {
        const [form, setForm] = useState({
          username: "",
          password: "",
        });

        const handleChange = (key) => (event) => {
          setForm((prev) => ({
            ...prev,
            [key]: event.target.value,
          }));
        };

        const handleSubmit = (event) => {
          event.preventDefault();
          alert(`用户名:${form.username}\n密码:${form.password}`);
        };

        return (
          <div className="card">
            <h2>Hook 实战:表单处理</h2>
            <form onSubmit={handleSubmit}>
              <input
                type="text"
                placeholder="用户名"
                value={form.username}
                onChange={handleChange("username")}
              />
              <input
                type="password"
                placeholder="密码"
                value={form.password}
                onChange={handleChange("password")}
              />
              <button type="submit">提交</button>
            </form>
          </div>
        );
      }

      ReactDOM.render(<UserForm />, document.getElementById("example"));
    </script>
  </body>
</html>

combine-demo

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - Combined Demo</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        padding: 30px;
      }
      .box {
        border: 1px solid #ddd;
        border-radius: 8px;
        padding: 20px;
        margin-bottom: 20px;
        width: 420px;
      }
      button {
        margin-right: 8px;
        padding: 8px 12px;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useState, useEffect, useRef, useCallback } = React;

      function useTimer() {
        const [seconds, setSeconds] = useState(0);

        useEffect(() => {
          const timer = setInterval(() => {
            setSeconds((prev) => prev + 1);
          }, 1000);

          return () => clearInterval(timer);
        }, []);

        return seconds;
      }

      function CombinedDemo() {
        const seconds = useTimer();
        const [count, setCount] = useState(0);
        const inputRef = useRef(null);

        const increase = useCallback(() => {
          setCount((prev) => prev + 1);
        }, []);

        const reset = useCallback(() => {
          setCount(0);
        }, []);

        useEffect(() => {
          if (inputRef.current) {
            inputRef.current.focus();
          }
        }, [count]);

        return (
          <div>
            <div className="box">
              <h2>Hook 实战:组合使用</h2>
              <p>计时器:{seconds} 秒</p>
              <p>计数器:{count}</p>
              <button onClick={increase}>加 1</button>
              <button onClick={reset}>重置</button>
            </div>

            <div className="box">
              <input ref={inputRef} defaultValue="聚焦状态" />
            </div>
          </div>
        );
      }

      ReactDOM.render(<CombinedDemo />, document.getElementById("example"));
    </script>
  </body>
</html>

useFetch

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - useFetch</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        padding: 30px;
      }
      .card {
        border: 1px solid #ddd;
        border-radius: 8px;
        padding: 20px;
        width: 420px;
      }
      button {
        padding: 8px 16px;
        margin-top: 12px;
        cursor: pointer;
      }
      ul {
        padding-left: 20px;
      }
    </style>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useState, useEffect } = React;

      function useFetch(url) {
        const [data, setData] = useState(null);
        const [loading, setLoading] = useState(true);
        const [error, setError] = useState(null);

        useEffect(() => {
          let isMounted = true;

          async function fetchData() {
            try {
              setLoading(true);
              const response = await fetch(url);
              const result = await response.json();

              if (isMounted) {
                setData(result);
                setError(null);
              }
            } catch (err) {
              if (isMounted) {
                setError(err.message || "请求失败");
              }
            } finally {
              if (isMounted) {
                setLoading(false);
              }
            }
          }

          fetchData();

          return () => {
            isMounted = false;
          };
        }, [url]);

        return { data, loading, error };
      }

      function FetchDemo() {
        const { data, loading, error } = useFetch("https://jsonplaceholder.typicode.com/posts?_limit=3");

        if (loading) return <div className="card">正在加载...</div>;
        if (error) return <div className="card">错误:{error}</div>;

        return (
          <div className="card">
            <h2>Hook 实战:useFetch</h2>
            <ul>
              {data && data.map((item) => <li key={item.id}>{item.title}</li>)}
            </ul>
          </div>
        );
      }

      ReactDOM.render(<FetchDemo />, document.getElementById("example"));
    </script>
  </body>
</html>

useLocalStorage

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>React Hook - useLocalStorage</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        padding: 30px;
      }
      .card {
        border: 1px solid #ddd;
        border-radius: 8px;
        padding: 20px;
        width: 420px;
      }
      input, button {
        width: 100%;
        box-sizing: border-box;
        margin-top: 10px;
        padding: 8px;
      }
    </style>
  </head>
  <body>
    <div id="example"></div>

    <script src="https://cdn.jsdelivr.net/npm/react@16.14.0/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.23.2/babel.min.js"></script>

    <script type="text/babel">
      const { useState, useEffect } = React;

      function useLocalStorage(key, initialValue) {
        const [value, setValue] = useState(() => {
          const storedValue = localStorage.getItem(key);
          return storedValue ? JSON.parse(storedValue) : initialValue;
        });

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

        return [value, setValue];
      }

      function LocalStorageDemo() {
        const [name, setName] = useLocalStorage("hook-demo-name", "React");

        return (
          <div className="card">
            <h2>Hook 实战:useLocalStorage</h2>
            <input
              type="text"
              value={name}
              onChange={(event) => setName(event.target.value)}
            />
            <button onClick={() => localStorage.removeItem("hook-demo-name")}>清除缓存</button>
          </div>
        );
      }

      ReactDOM.render(<LocalStorageDemo />, document.getElementById("example"));
    </script>
  </body>
</html>