React Hooks进阶

深入LearningReact Hooks进阶knowledge, includinguseEffect, useContext, useReducer, useCallback, useMemoetc.advancedHooks using

1. useEffect Hook深入understanding

useEffect Hook用于processingcomponent 副作用, such asdata获取, subscribe or 手动DOMoperation.

1.1 useEffect 依赖项

useEffect接收两个parameter: 一个副作用function and 一个依赖项array.

// 依赖项 for 空array: 只 in component挂载时执行一次
useEffect(() => {
  console.log('Component mounted');
  return () => {
    console.log('Component will unmount');
  };
}, []);

// 依赖项 for 具体值: 当依赖项变化时执行
useEffect(() => {
  console.log(`Count changed to: ${count}`);
}, [count]);

// 无依赖项: 每次渲染 after 都执行
useEffect(() => {
  console.log('Component re-rendered');
});

提示

useEffect cleanfunction会 in component卸载 or 依赖项变化时执行, 用于清除副作用.

1.2 usinguseEffect获取data

function DataFetchingComponent() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://api.example.com/data');
        const result = await response.json();
        setData(result);
        setLoading(false);
      } catch (error) {
        console.error('Error fetching data:', error);
        setLoading(false);
      }
    };
    
    fetchData();
  }, []);
  
  if (loading) {
    return <div>Loading...</div>;
  }
  
  return (
    <div>
      {data.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  );
}

2. useContext Hook

useContext Hook用于consumeContext, 避免了Context.Consumer 嵌套.

// creationContext
const ThemeContext = createContext('light');

// providingContext
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedComponent />
    </ThemeContext.Provider>
  );
}

// consumeContext
function ThemedComponent() {
  const theme = useContext(ThemeContext);
  
  return (
    <div style={{ 
      backgroundColor: theme === 'dark' ? '#333' : '#fff',
      color: theme === 'dark' ? '#fff' : '#333',
      padding: '20px'
    }}>
      Current theme: {theme}
    </div>
  );
}

3. useReducer Hook

useReducer Hook is useState 替代solutions, 适用于 complex statusmanagement.

// 定义reducerfunction
function counterReducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    case 'RESET':
      return { count: 0 };
    case 'ADD':
      return { count: state.count + action.payload };
    default:
      return state;
  }
}

// usinguseReducer
function Counter() {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });
  
  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
      <button onClick={() => dispatch({ type: 'ADD', payload: 5 })}>Add 5</button>
    </div>
  );
}

4. useCallback and useMemo Hook

useCallback and useMemo用于optimizationcomponentperformance, 避免不必要 重 new 计算 and 渲染.

4.1 useCallback Hook

useCallback返回一个记忆化 callbackfunction, 只 has 当依赖项变化时才会重 new creation.

function ParentComponent() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState('Hello');
  
  // useCallback记忆化callbackfunction
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

// usingReact.memo避免不必要 重 new 渲染
const ChildComponent = React.memo(({ onClick }) => {
  console.log('ChildComponent rendered');
  return <button onClick={onClick}>Click me</button>;
});

4.2 useMemo Hook

useMemo返回一个记忆化 值, 只 has 当依赖项变化时才会重 new 计算.

function ExpensiveComponent() {
  const [count, setCount] = useState(0);
  const [number, setNumber] = useState(10);
  
  // useMemo记忆化计算结果
  const expensiveResult = useMemo(() => {
    console.log('Calculating expensive result...');
    let result = 0;
    for (let i = 0; i < 100000000; i++) {
      result += i;
    }
    return result;
  }, [number]);
  
  return (
    <div>
      <p>Count: {count}</p>
      <p>Number: {number}</p>
      <p>Expensive Result: {expensiveResult}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <button onClick={() => setNumber(number + 1)}>Increment Number</button>
    </div>
  );
}

5. useRef Hook

useRef Hook用于creation一个可变 refobject, 用于访问DOM元素 or store任意值.

function RefComponent() {
  const inputRef = useRef(null);
  const countRef = useRef(0);
  
  const handleFocus = () => {
    inputRef.current.focus();
  };
  
  const handleClick = () => {
    countRef.current += 1;
    console.log('Clicked:', countRef.current);
  };
  
  return (
    <div>
      <input ref={inputRef} type="text" placeholder="Enter text" />
      <button onClick={handleFocus}>Focus Input</button>
      <button onClick={handleClick}>Click Me</button>
    </div>
  );
}

6. 自定义Hook

自定义Hook允许我们将component逻辑提取 to reusable functionin.

// 自定义Hook: useLocalStorage
function useLocalStorage(key, initialValue) {
  //  from localStorage获取初始值
  const [value, setValue] = useState(() => {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });
  
  // updatelocalStorage并设置status
  const setLocalStorageValue = (newValue) => {
    try {
      setValue(newValue);
      localStorage.setItem(key, JSON.stringify(newValue));
    } catch (error) {
      console.error(error);
    }
  };
  
  return [value, setLocalStorageValue];
}

// using自定义Hook
function LocalStorageComponent() {
  const [name, setName] = useLocalStorage('name', '');
  
  return (
    <div>
      <input 
        type="text" 
        value={name} 
        onChange={(e) => setName(e.target.value)} 
        placeholder="Enter your name" 
      />
      <p>Hello, {name}!</p>
    </div>
  );
}

练习 1: usinguseEffect获取data

  1. creation一个component, usinguseEffect from API获取data
  2. implementation加载status and errorprocessing
  3. usinguseCallbackoptimizationeventprocessingfunction

练习 2: creation自定义Hook

  1. creation一个useDebounce自定义Hook, 用于防抖processing
  2. in 搜索componentinusing该Hook, implementation输入防抖