每位开发者必须知道的 20 个基本 React 技巧 🚀

1,285 阅读4分钟

React 是一个非常强大的工具,但要真正掌握它,光学基础还不够,还需要了解一些鲜为人知的小技巧,以让开发过程更加顺畅。下面是我个人整理的 20 个 React 技巧,这些技巧可以显著提升开发效率,帮助你编写更简洁、更高效的代码。让我们一起来看看这些实用的例子吧!

cover.jpg

  1. 使用短路求值进行条件渲染

    使用短路求值代替冗长的 if 语句来进行条件渲染。

    {isLoading && <Spinner />}
    

    这样只有当 isLoadingtrue 时才会渲染 <Spinner />,保持你的 JSX 简洁明了。

  2. 使用 classnames 库实现动态类名

    classnames 库可以让你轻松地根据条件应用不同的类名。

    npm install classnames
    
    import classNames from 'classnames';
    ​
    const buttonClass = classNames({
      'btn': true,
      'btn-primary': isPrimary,
      'btn-secondary': !isPrimary,
    });
    ​
    <button className={buttonClass}>Click Me</button>
    
  3. 使用 useMemo 缓存复杂计算结果

    如果某个计算过程比较复杂且耗时,可以使用 useMemo 进行缓存,这样 React 就不会在不必要的时候重新计算,提高性能。

    const sortedData = useMemo(() => data.sort(), [data]);
    

    这段代码只有在 data 发生变化时才会重新计算 sortedData

  4. 使用 useEffect 对输入进行防抖处理

    通过对输入变化进行防抖处理,避免频繁的重新渲染。

    const [value, setValue] = useState('');
    const [debouncedValue, setDebouncedValue] = useState('');
    ​
    useEffect(() => {
      const handler = setTimeout(() => setDebouncedValue(value), 500);
      return () => clearTimeout(handler);
    }, [value]);
    ​
    <input value={value} onChange={(e) => setValue(e.target.value)} />
    
  5. 使用自定义 Hook 实现可重用逻辑

    将逻辑封装到自定义 Hook 中,以便在多个组件中复用。

    function useFetch(url) {
      const [data, setData] = useState(null);
    ​
      useEffect(() => {
        fetch(url).then(res => res.json()).then(setData);
      }, [url]);
    ​
      return data;
    }
    ​
    const Component = () => {
      const data = useFetch('/api/data');
      return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
    };
    
  6. 使用 React.lazy 实现组件的懒加载

    通过拆分组件实现懒加载,可以优化页面的加载时间。

    const LazyComponent = React.lazy(() => import('./LazyComponent'));
    ​
    function App() {
      return (
        <React.Suspense fallback={<div>Loading...</div>}>
          <LazyComponent />
        </React.Suspense>
      );
    }
    
  7. 使用 useRef 获取之前的 PropsState

    如果需要访问之前的状态值,可以使用 useRef

    const [count, setCount] = useState(0);
    const prevCount = useRef(count);
    ​
    useEffect(() => {
      prevCount.current = count;
    }, [count]);
    ​
    console.log(`Previous: ${prevCount.current}, Current: ${count}`);
    
  8. 使用 useCallback 传递函数以避免不必要的重新渲染

    如果一个函数不需要改变,可以使用 useCallback 进行缓存,避免每次重新生成,从而减少不必要的重新渲染。

    const increment = useCallback(() => setCount(count + 1), [count]);
    
  9. 解构 Props 使代码更加简洁

    在函数参数中直接解构 props,使代码更加简洁明了。

    const User = ({ name, age }) => (
      <div>{name} is {age} years old</div>
    );
    
  10. 使用 React.Fragment 分组元素,避免额外的 div 标签

    使用 React.Fragment 可以包裹元素而不添加额外的 DOM 节点。

    <>
      <p>Paragraph 1</p>
      <p>Paragraph 2</p>
    </>
    
  11. 使用错误边界捕获 JavaScript 错误

    在子组件中捕获错误,以防止整个应用崩溃。

    class ErrorBoundary extends React.Component {
      state = { hasError: false };
    ​
      static getDerivedStateFromError() {
        return { hasError: true };
      }
    ​
      render() {
        if (this.state.hasError) return <h1>Something went wrong.</h1>;
        return this.props.children;
      }
    }
    
  12. 使用 PropTypes 进行 Prop 验证

    通过定义 prop 类型,可以及早捕获错误,确保组件使用正确的数据类型。

    import PropTypes from 'prop-types';
    ​
    function MyComponent({ name }) {
      return <div>{name}</div>;
    }
    ​
    MyComponent.propTypes = {
      name: PropTypes.string.isRequired,
    };
    
  13. 使用 useReducer 管理复杂的状态

    对于复杂的状态逻辑,useReducer 可以更高效地管理状态。

    const initialState = { count: 0 };
    ​
    function reducer(state, action) {
      switch (action.type) {
        case 'increment': return { count: state.count + 1 };
        case 'decrement': return { count: state.count - 1 };
        default: return state;
      }
    }
    ​
    const [state, dispatch] = useReducer(reducer, initialState);
    
  14. 使用 useLayoutEffect 进行 DOM 操作

    DOM 更新后、浏览器重绘前运行效果,以确保 DOM 操作及时生效。

    useLayoutEffect(() => {
      console.log("Layout effect");
    }, []);
    
  15. 使用 ContextuseContext 封装状态逻辑

    使用 Context 创建全局状态,避免层层传递 props 的麻烦。

    const ThemeContext = React.createContext();
    ​
    function MyComponent() {
      const theme = useContext(ThemeContext);
      return <div style={{ background: theme }}>Hello!</div>;
    }
    
  16. 避免在 JSX 中定义内联函数

    JSX 中定义内联函数会导致组件重新渲染。应将这些函数定义在组件外部,以避免不必要的性能开销。

    const handleClick = () => console.log("Clicked");
    ​
    <button onClick={handleClick}>Click Me</button>
    
  17. JSX 中使用可选链(?.)安全访问属性

    使用可选链(?.)可以优雅地处理 nullundefined 值,避免访问不存在属性时报错。

    <p>{user?.name}</p>
    
  18. 使用 key 属性来避免重新渲染问题

    在渲染列表时,一定要使用唯一的 key 值,以确保 React 正确管理每个元素,避免渲染问题。

    {items.map(item => (
      <div key={item.id}>{item.name}</div>
    ))}
    
  19. 使用命名导出来更好地控制组件的导入

    使用命名导出可以更方便地按需导入特定的组件。

    export const ComponentA = () => <div>A</div>;
    export const ComponentB = () => <div>B</div>;
    

    然后按需导入组件:

    import { ComponentA } from './Components';
    
  20. 可重用组件模式:高阶组件(HOCs

    使用高阶组件(HOCs)包裹组件,以添加额外的逻辑功能。

    function withLogging(WrappedComponent) {
      return function Wrapped(props) {
        console.log('Component Rendered');
        return <WrappedComponent {...props} />;
      };
    }
    ​
    const MyComponentWithLogging = withLogging(MyComponent);
    

掌握这些技巧将帮助你编写更简洁、可读性更强且高效的 React 代码!