React18 Hooks,useImperativeHandle,useLayoutEffect,自定义Hooks(打印生命周期,context获取数据..)

56 阅读3分钟

useImperativeHandle()

image.png

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

const HelloZM = memo(
  forwardRef((props, ref) => {
    const zmInputRef = useRef();
    // 子组件对父组件传入的ref进行处理
    useImperativeHandle(ref, () => {
      return {
        //相当于返回给父组件的current对象
        focus() {
          zmInputRef.current.focus();
        },
        setValue(value) {
          zmInputRef.current.value = value;
        },
      };
    });
    return <input type="text" ref={zmInputRef} />;
  })
);

const App = memo(() => {
  const titleRef = useRef();
  const inputRef = useRef();

  function handleDOM() {
    console.log(inputRef.current); //子组件通过useImperativeHandle暴露出来的对象 {focus: ƒ, setValue: ƒ}
    // 在父组件中操作子组件
    inputRef.current.focus();
    inputRef.current.setValue("hello ww");
  }

  return (
    <div>
      <h2 ref={titleRef}>useImperativeHandle App Page</h2>
      <HelloZM ref={inputRef} />
      <button onClick={handleDOM}>DOM操作</button>
    </div>
  );
});
export default App;

useLayoutEffect()

image.png

执行时机:1 2 3

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

const App = memo(() => {
  const [count, setCount] = useState(0);

  useLayoutEffect(() => {
    console.log("2useLayoutEffect");
  });

  useEffect(() => {
    console.log("3useEffect");
  });

  console.log("1App render");

  return (
    <div>
      <h2>useLayoutEffect App Page count:{count}</h2>
      <button onClick={(e) => setCount(count + 1)}>+1</button>
    </div>
  );
});
export default App;

计数器闪烁现象:

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

const ChangeNum = memo(() => {
  const [count, setCount] = useState(100);

  useEffect(() => {
    //在dom渲染之后执行,会出现闪烁,0 => 90
    console.log("useEffect");
    if (count === 0) {
      setCount(Math.random() + 90);
    }
  }, [count]);

  console.log("ChangeNum page render");

  return (
    <div>
      <h2>ChangeNum count:{count}</h2>
      <button onClick={(e) => setCount(0)}>set 0</button>
    </div>
  );
});
export default ChangeNum;
import React, { memo, useLayoutEffect, useState } from "react";

const ChangeNum2 = memo(() => {
  const [count, setCount] = useState(100);

  useLayoutEffect(() => {
    //在dom渲染之后执行,会出现闪烁,0 => 90
    console.log("useEffect");
    if (count === 0) {
      setCount(Math.random() + 90);
    }
  }, [count]);

  console.log("ChangeNum page render");

  return (
    <div>
      <h2>ChangeNum count:{count}</h2>
      <button onClick={(e) => setCount(0)}>set 0</button>
    </div>
  );
});
export default ChangeNum2;

自定义Hooks

  • 打印生命周期
import React, { memo, useEffect, useState } from "react";

function useLogLife(cName) {
  useEffect(() => {
    console.log(cName + "组件被创建");
    return () => {
      console.log(cName + "组件被销毁");
    };
  }, []);
}

const Home = memo(() => {
  useLogLife("home");
  return <h1>Home Page</h1>;
});

const About = memo(() => {
  useLogLife("about");
  return <h1>About Page</h1>;
});

const App = memo(() => {
  const [isShow, setIsShow] = useState(true);
  useLogLife("app");
  return (
    <div>
      <h2>自定义 App hooks</h2>
      <div>
        {isShow && <Home />}
        {isShow && <About />}
      </div>
      <button onClick={(e) => setIsShow(!isShow)}> isShow?</button>
    </div>
  );
});
export default App;
  • context获取数据
import { createContext } from "react";
const UserContext = createContext();
const TokenContext = createContext();
export { UserContext, TokenContext };
import { TokenContext, UserContext } from "./pages-learn-hooks/自定义hooks/context";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <UserContext.Provider value={{ name: "wzm", age: 21 }}>
    <TokenContext.Provider value={"zm_token"}>
      <App />
    </TokenContext.Provider>
  </UserContext.Provider>
);
import { useContext } from "react";
import { TokenContext, UserContext } from "../context";
function useUserToken() {
  const user = useContext(UserContext);
  const token = useContext(TokenContext);

  return [user, token];
}
export default useUserToken;

在组件中使用token

import React, { memo, useState } from "react";
import { useUserToken } from "./hooks";

const Home = memo(() => {
  const [user, token] = useUserToken();
  return (
    <h1>
      Home Page:{user.name}-{user.age}-{token}
    </h1>
  );
});

const About = memo(() => {
  const [user, token] = useUserToken();
  return (
    <h1>
      About Page:{user.name}-{user.age}-{token}
    </h1>
  );
});

const App = memo(() => {
  const [isShow, setIsShow] = useState(true);
  return (
    <div>
      <h2>自定义 App hooks</h2>
      <div>
        {isShow && <Home />}
        {isShow && <About />}
      </div>
      <button onClick={(e) => setIsShow(!isShow)}> isShow?</button>
    </div>
  );
});
export default App;

image.png

监听窗口滚动位置

import { useEffect, useState } from "react";
function useScrollPosition() {
  const [scrollX, setScrollX] = useState(0);
  const [scrollY, setScrollY] = useState(0);
  useEffect(() => {
    function handleScroll() {
      setScrollX(window.scrollX);
      setScrollY(window.scrollY);
    }
    window.addEventListener("scroll", handleScroll);
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);
  return [scrollX, scrollY];
}
export default useScrollPosition;
import React, { memo, useState } from "react";
import { useScrollPosition } from "./hooks";
import "./style.css";

const Home = memo(() => {
  const [scrollX, scrollY] = useScrollPosition();
  return (
    <h1>
      Home Page:{scrollX}-{scrollY}
    </h1>
  );
});

const About = memo(() => {
  const [scrollX, scrollY] = useScrollPosition();
  return (
    <h1>
      About Page:{scrollX}-{scrollY}
    </h1>
  );
});

const App = memo(() => {
  const [isShow, setIsShow] = useState(true);
  return (
    <div>
      <h2>自定义 App hooks</h2>
      <div className="app">
        {isShow && <Home />}
        {isShow && <About />}
      </div>
      <button onClick={(e) => setIsShow(!isShow)}> isShow?</button>
    </div>
  );
});
export default App;

localStorage

import React, { memo } from "react";
import useLocalStorage from "./hooks/useLocalStorage";

const App = memo(() => {
  //通过key,直接从localStorage中获取一个数据
  // const [token, setToken] = useState(localStorage.getItem("token"));
  // useEffect(() => {
  //   localStorage.setItem("token", token);
  // }, [token]);
  const [token, setToken] = useLocalStorage("token");

  function setTokenHandle() {
    setToken("zm_token_useLocalStorage");
  }

  // const [avatarUrl, setAvatarUrl] = useState(localStorage.getItem("avatarUrl"));
  // useEffect(() => {
  //   localStorage.setItem("avatarUrl", avatarUrl);
  // }, [avatarUrl]);
  const [avatarUrl, setAvatarUrl] = useLocalStorage("avatarUrl");

  function setAvatarUrlHandle() {
    setAvatarUrl("http://www.zm.com/useLocalStorage/a.jgp");
  }

  return (
    <div>
      <h2>自定义 App hooks Page</h2>
      <button onClick={setTokenHandle}>setToken({token})</button>
      <button onClick={setAvatarUrlHandle}>setAvatar({avatarUrl})</button>
    </div>
  );
});
export default App;
import { useEffect, useState } from "react";
function useLocalStorage(key) {
  //   const [data, setData] = useState(JSON.parse(localStorage.getItem(key)));

  //useState()可以传递一个函数,立即执行
  //   1.从localStorage中获取数据,并且数据创建组件的state
  const [data, setData] = useState(() => {
    const item = localStorage.getItem(key);
    if (!item) return "";
    return JSON.parse(item);
  });

  //   2.监听data改变,一旦发生改变就存储data最新值
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(data));
  }, [data]);

  //   3.将data/setData的操作返回给组件,让组件可以使用和修改值
  return [data, setData];
}
export default useLocalStorage;