Skip to content

概述

React 是一个用于构建用户界面的 JavaScript 库。它允许开发人员创建可重用的 UI 组件,这些组件可以独立于其他组件进行渲染和更新。

React 的主要特点是声明式编程模型,其中开发者使用 JSX(JavaScript XML)语法来描述 UI 组件的结构和行为。这种声明性编程模型使得代码更加简洁、易于维护和扩展。

React 还提供了许多有用的功能和工具,如虚拟 DOM、组件生命周期钩子、状态管理和路由等。这些功能和工具帮助开发者更高效地构建复杂的用户界面应用程序。

常用Hooks

  1. useState 用途:用于在函数组件中添加状态。

示例:

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

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

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;
  1. useEffect 用途:用于执行副作用操作,如数据获取、订阅或手动更改 DOM。

示例:

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

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;

    return () => {
      // 清理副作用
      document.title = 'React App';
    };
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

export default Example;
  1. useContext 用途:用于访问 React Context。

示例:

jsx
import React, { createContext, useContext, useState } from 'react';

const ThemeContext = createContext('light');

function App() {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={theme}>
      <div>
        <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
          Toggle Theme
        </button>
        <ChildComponent />
      </div>
    </ThemeContext.Provider>
  );
}

function ChildComponent() {
  const theme = useContext(ThemeContext);
  return <div style={{ backgroundColor: theme === 'dark' ? 'black' : 'white' }}>Child Component</div>;
}

export default App;
  1. useReducer 用途:用于替代 useState 来管理更复杂的组件状态。

示例:

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

const initialState = { count: 0 };

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

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

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}

export default Counter;
  1. useCallback 性能优化,防止不必要渲染 用途:用于创建带有稳定引用的回调函数。

示例:

jsx
import React, { useState, useCallback } from 'react';

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

  const callback = useCallback(() => {
    console.log('Callback called');
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent callback={callback} />
    </div>
  );
}

function ChildComponent({ callback }) {
  return (
    <div>
      <button onClick={callback}>Call Callback</button>
    </div>
  );
}

export default ParentComponent;
  1. useMemo 性能优化,防止不必要渲染 用途:useMemo用于避免不必要的重新计算。它会 memoize(缓存)一个值,并仅当其依赖项发生变化时才重新计算这个值。 示例:
jsx
import React, { useState, useMemo } from 'react';

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

  const heavyComputation = useMemo(() => {
    console.log('Heavy computation');
    return Array.from({ length: 1000000 }, () => Math.random());
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent data={heavyComputation} />
    </div>
  );
}

function ChildComponent({ data }) {
  return (
    <div>
      <p>Data Length: {data.length}</p>
    </div>
  );
}

export default ParentComponent;
  1. useRef 用途:用于获取 DOM 元素或组件的引用。 示例:
jsx
import React, { useRef } from 'react';

function TextInputWithFocusButton() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    // 当按钮被点击时,使文本框获得焦点
    inputEl.current.focus();
  };

  return (
    <div>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </div>
  );
}

export default TextInputWithFocusButton;
  1. useImperativeHandle

用途:用于自定义暴露给父组件的 ref 对象。 示例:

jsx
import React, { useRef, useImperativeHandle, forwardRef } from 'react';

function CustomTextInput(props, ref) {
  const inputEl = useRef(null);

  useImperativeHandle(ref, () => ({ // 把子组件方法暴露给父组件,类似vue3 defineExpose
    focus: () => {
      inputEl.current.focus();
    }
  }));

  return (
    <input ref={inputEl} type="text" />
  );
}
// forwardRef 允许我们创建一个组件,该组件可以暴露一个 ref 对象,父组件通过该ref获取子组件实例
const CustomTextInputWithRef = forwardRef(CustomTextInput);

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

  const onButtonClick = () => {
    customTextInput.current.focus();
  };

  return (
    <div>
      <CustomTextInputWithRef ref={customTextInput} />
      <button onClick={onButtonClick}>Focus the input</button>
    </div>
  );
}

export default ParentComponent;
  1. useLayoutEffect 用途:在组件渲染后,在浏览器绘制之前执行。 示例:
jsx
import React, { useState, useLayoutEffect } from 'react';

function Example() {
  const [width, setWidth] = useState(window.innerWidth);

  useLayoutEffect(() => {
    function handleResize() {
      setWidth(window.innerWidth);
    }

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return (
    <div>
      <p>Window width: {width}px</p>
    </div>
  );
}

export default Example;

react 常用api react.memo react.memo 是一个高阶组件(Higher-Order Component, HOC),用于优化函数组件的性能。它可以避免不必要的重新渲染,提高应用的性能。下面详细介绍 react.memo 的用法和应用场景。

  1. 基本用法 react.memo 接受一个函数组件,并返回一个新的组件。这个新组件会在其 props 发生变化时才会重新渲染。

  2. 示例 假设有一个简单的函数组件,我们希望只有当 props 发生变化时才重新渲染。

jsx
import React, { memo } from 'react';

const Greeting = memo(({ name }) => {
  console.log('Rendering Greeting');
  return <h1>Hello, {name}!</h1>;
});

function App() {
  const [name, setName] = React.useState('World');

  return (
    <div>
      <Greeting name={name} />
      <button onClick={() => setName('Ali')}>Change Name</button>
    </div>
  );
}

export default App;

在这个例子中,Greeting 组件被 memo 包装后,只有当 name 发生变化时才会重新渲染。

  1. 自定义比较函数 默认情况下,react.memo 使用浅层比较(shallow comparison)来检查 props 是否发生变化。如果你需要更精细的比较逻辑,可以传递一个自定义的比较函数作为第二个参数。
jsx
import React, { memo } from 'react';

const Greeting = memo(
  ({ name }) => {
    console.log('Rendering Greeting');
    return <h1>Hello, {name}!</h1>;
  },
  (prevProps, nextProps) => {
    // 自定义比较逻辑
    return prevProps.name === nextProps.name;
  }
);

function App() {
  const [name, setName] = React.useState('World');

  return (
    <div>
      <Greeting name={name} />
      <button onClick={() => setName('Ali')}>Change Name</button>
    </div>
  );
}

export default App;

注意:memo底层通过Object.is判断props是否发生变化,当传递引用类型的props,父组件更新时都会重新创建,所以子组件每次都会更新,在父组件配合useMemo和useCallback创建引用型props参数可以避免这个问题