React 函数式组件使用手册

Published: · LastMod: April 07, 2024 · 425 words

React Hooks Functional对应class Component生命周期写法 🔗

componentDidMount 🔗

1
2
3
useEffect(() => {
  // Your code here
}, []);

componentDidUpdate 🔗

1
2
3
useEffect(() => {
  // Your code here
}, [yourDependency]);

componentWillUnmount 🔗

1
2
3
4
5
6
useEffect(() => {
  // componentWillUnmount
  return () => {
     // Your code here
  }
}, [yourDependency]);

Ref.current作为useEffect的依赖 🔗

Mutable values like ‘ref.current’ aren’t valid dependencies because mutating them doesn’t re-render the component.

因为引用不会触发渲染,因此不会触发useEffect渲染

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const Foo = () => {
  const [, render] = useReducer(p => !p, false);
  const ref = useRef(0);

  const onClickRender = () => {
    ref.current += 1;
    render();
  };

  const onClickNoRender = () => {
    ref.current += 1;
  };

  useEffect(() => {
    console.log('ref changed');
  }, [ref.current]);

  return (
    <>
      <button onClick={onClickRender}>Render</button>
      <button onClick={onClickNoRender}>No Render</button>
    </>
  );
};

正确获取组件ref实例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const Component = () => {
  const [isMounted, toggle] = useReducer((p) => !p, true);
  const [elementRect, setElementRect] = useState();

  const handleRect = useCallback((node) => {
    setElementRect(node?.getBoundingClientRect());
  }, []);

  return (
    <>
      {isMounted && <div ref={handleRect}>Example</div>}
      <button onClick={toggle}>Toggle</button>
      <pre>{JSON.stringify(elementRect, null, 2)}</pre>
    </>
  );
};

动态创建portal 🔗

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { memo, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';

const Portal = ({ id, children }) => {
  
  const el = useRef(document.getElementById(id) || document.createElement('div'));
  const [dynamic] = useState(!el.current.parentElement);
  
  useEffect(() => {
    
    if (dynamic) {
      el.current.id = id;
      document.body.appendChild(el.current);
    }
    
    return () => {
      if (dynamic && el.current.parentElement) {
        el.current.parentElement.removeChild(el.current);
      }
    }
    
  }, [id]);
  
  return createPortal(children, el.current);
};
export default memo(Portal);