2025年面试中常见的 React 90个问题及答案,持续更新..

1. 什么是 React?

答案:React 是一个用于构建用户界面的 JavaScript 库。它允许开发者通过组件的方式构建复杂的 UI,支持单向数据流和虚拟 DOM,从而提高性能。

2. 解释虚拟 DOM 的概念。

答案:虚拟 DOM 是 React 使用的一种优化技术。它是对真实 DOM 的轻量级表示。每当组件的状态发生变化时,React 会先在虚拟 DOM 中进行更新,然后通过比较(Diffing)算法找出最小的变更,最后将这些变更应用到真实 DOM 中。这种方式减少了直接操作 DOM 的开销,提高了性能。

3. React 中的状态和属性有什么区别?

答案

  • 状态(State):组件内部的数据,通常通过 this.setState 更新。状态是可变的,组件的局部状态。
  • 属性(Props):从父组件传递到子组件的数据,子组件无法直接修改。属性是不可变的,用于组件之间的通信。

4. 什么是组件生命周期?

答案:组件生命周期是指组件在其存在期间的不同阶段,包括初始化、更新和卸载。React 提供了多个生命周期方法,例如 componentDidMountcomponentDidUpdatecomponentWillUnmount,用于在这些阶段执行特定的操作。

5. React 中的 Hooks 是什么?

答案:Hooks 是 React 16.8 引入的一种新特性,允许在函数组件中使用状态和其他 React 特性。常用的 Hooks 包括 useStateuseEffectuseContext

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

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

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]);

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

6. 解释 useEffect 的作用。

答案useEffect 是一个 Hook,用于处理副作用(如数据获取、订阅或手动 DOM 操作)。它在组件渲染后执行,可以指定依赖项数组,以控制何时重新运行副作用。

useEffect(() => {
  // 进行副作用操作
  return () => {
    // 清理操作
  };
}, [依赖项]);

7. 什么是高阶组件(HOC)?

答案:高阶组件是一个函数,接受一个组件作为参数并返回一个新组件。它用于复用组件逻辑。常见的用途包括条件渲染、数据获取等。

const withLogging = (WrappedComponent) => {
  return class extends React.Component {
    componentDidMount() {
      console.log('组件已挂载');
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
};

8. 如何在 React 中处理表单?

答案:可以使用受控组件和非受控组件来处理表单。受控组件通过 React 状态管理输入值,而非受控组件使用 ref 直接访问 DOM 元素。

受控组件示例:

const MyForm = () => {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <input type="text" value={inputValue} onChange={handleChange} />
  );
};

9. React 的 context 是什么?

答案context 是 React 提供的一种方式,用于在组件树中传递数据,而不必通过每层组件的 props。它适用于全局数据,如用户信息、主题或语言设置。

const MyContext = React.createContext();

const MyProvider = ({ children }) => {
  const value = { name: 'John' };
  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
};

const MyComponent = () => {
  const context = React.useContext(MyContext);
  return <div>{context.name}</div>;
};

10. React 中的 key 属性有什么作用?

答案key 属性用于标识列表中的每个元素,帮助 React 更高效地更新和渲染列表。它应该是唯一的且稳定的,以便 React 能够识别哪些元素发生了变化、添加或删除。

const items = [1, 2, 3];
const ItemList = () => (
  <ul>
    {items.map(item => (
      <li key={item}>{item}</li>
    ))}
  </ul>
);

11. 如何在 React 中进行条件渲染?

答案:可以使用 JavaScript 的条件语句(如三元运算符、逻辑与运算符)来实现条件渲染。

const ConditionalRendering = ({ isLoggedIn }) => (
  <div>
    {isLoggedIn ? <p>欢迎回来!</p> : <p>请登录.</p>}
  </div>
);

12. React 中的 fragment 是什么?

答案Fragment 是一个用于包装多个子元素而不在 DOM 中添加额外节点的组件。它可以减少不必要的 DOM 层级。

const MyComponent = () => (
  <React.Fragment>
    <h1>标题</h1>
    <p>内容</p>
  </React.Fragment>
);

13. 什么是懒加载(Lazy Loading)?

答案:懒加载是指在需要时才加载组件或模块,而不是在应用启动时加载所有内容。React 提供了 React.lazySuspense 来支持懒加载。

const LazyComponent = React.lazy(() => import('./LazyComponent'));

const App = () => (
  <React.Suspense fallback={<div>加载中...</div>}>
    <LazyComponent />
  </React.Suspense>
);

14. 如何优化 React 应用的性能?

答案:优化 React 应用的性能可以通过以下方式实现:

  • 使用 React.memo:防止不必要的重渲染。
  • 使用 shouldComponentUpdate:在类组件中手动控制更新。
  • 使用 useMemouseCallback:缓存计算值和回调函数。
  • 懒加载组件:减少初始加载时间。
  • 避免深层次的组件嵌套:降低复杂性。

15. React 中如何使用 Redux 进行状态管理?

答案:Redux 是一个状态管理库,通常与 React 一起使用。在 Redux 中,应用的状态存储在一个单一的 store 中,状态的变化通过 dispatch actions 和 reducer 来实现。

Redux 示例:

import { createStore } from 'redux';

const initialState = { count: 0 };

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    default:
      return state;
  }
};

const store = createStore(reducer);

在组件中使用 Redux:

import { useSelector, useDispatch } from 'react-redux';

const Counter = () => {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>增加</button>
    </div>
  );
};

2025年面试中常见的 React 问题及答案(续)

继续增加更多常见的 React 面试问题及其答案,以帮助你在求职时更好地准备。

16. 如何使用 Redux 中间件?

答案:Redux 中间件是用于扩展 Redux 的功能的一个工具,常见的中间件包括 redux-thunkredux-saga。它们可以处理异步操作和增强 store 的能力。

使用 redux-thunk 示例:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const store = createStore(reducer, applyMiddleware(thunk));

// 异步 action 示例
const fetchData = () => {
  return (dispatch) => {
    fetch('https://api.example.com/data')
      .then((response) => response.json())
      .then((data) => {
        dispatch({ type: 'FETCH_SUCCESS', payload: data });
      });
  };
};

17. 什么是 React Router?如何使用?

答案:React Router 是一个用于在 React 应用中实现路由的库。它允许开发者在单页应用中创建和管理不同的页面。

基本用法示例:

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

const App = () => (
  <Router>
    <Switch>
      <Route path="/" exact component={Home} />
      <Route path="/about" component={About} />
    </Switch>
  </Router>
);

18. 如何处理 React 中的错误边界?

答案:错误边界是 React 16 引入的功能,用于捕获子组件中的 JavaScript 错误并显示备用 UI。实现错误边界需要创建一个类组件,并实现 componentDidCatchgetDerivedStateFromError 方法。

示例:

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    console.error('错误边界捕获到错误:', error, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>出错了!</h1>;
    }

    return this.props.children;
  }
}

// 使用错误边界
<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

19. React 中的 useReducer Hook 是什么?何时使用?

答案useReducer 是一个 Hook,用于管理复杂状态逻辑。它接受一个 reducer 函数和初始状态,返回当前状态和 dispatch 函数。适合在状态更新逻辑复杂的场景下使用,例如表单处理或多状态管理。

示例:

const initialState = { count: 0 };

const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
};

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

  return (
    <div>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>增加</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>减少</button>
    </div>
  );
};

20. React 中的 StrictMode 是什么?

答案StrictMode 是 React 提供的一种工具,用于突出显示应用中的潜在问题。在开发模式下,它会检查子组件的生命周期方法、过时的 API 使用以及其他潜在问题。

示例:

<React.StrictMode>
  <App />
</React.StrictMode>

21. 如何在 React 中使用 CSS Modules?

答案:CSS Modules 是一种局部作用域的 CSS 解决方案,避免命名冲突。通过将 CSS 文件命名为 .module.css,可以在组件中导入并使用。

示例:

/* styles.module.css */
.container {
  background-color: blue;
}
import styles from './styles.module.css';

const MyComponent = () => {
  return <div className={styles.container}>Hello World</div>;
};

22. 解释 React 中的 useContext Hook。

答案useContext 是一个 Hook,用于在函数组件中访问 React Context。它简化了在组件树中传递数据的过程,避免了多层嵌套的 props 传递。

示例:

const MyContext = React.createContext();

const MyProvider = ({ children }) => {
  const value = 'Hello from Context';
  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
};

const MyComponent = () => {
  const contextValue = useContext(MyContext);
  return <div>{contextValue}</div>;
};

23. 如何在 React 中实现懒加载图片?

答案:可以使用 Intersection Observer API 来实现懒加载图片。当图片进入视口时,再加载该图片。

示例:

const LazyImage = ({ src, alt }) => {
  const [isVisible, setIsVisible] = useState(false);
  
  const imgRef = useRef();

  useEffect(() => {
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        setIsVisible(true);
        observer.disconnect();
      }
    });

    if (imgRef.current) {
      observer.observe(imgRef.current);
    }

    return () => {
      observer.disconnect();
    };
  }, []);

  return <img ref={imgRef} src={isVisible ? src : ''} alt={alt} />;
};

24. React 中的 useMemouseCallback 有什么区别?

答案

  • useMemo:用于缓存计算结果,避免在每次渲染时重复计算。适用于性能优化。

    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
    
  • useCallback:用于缓存函数实例,避免在每次渲染时创建新函数。适用于传递给子组件的回调函数。

    const memoizedCallback = useCallback(() => { doSomething(a); }, [a]);
    

25. 如何在 React 中处理错误?

答案:可以使用 try-catch 语句来处理错误,或者使用错误边界捕获子组件中的错误。对于异步操作,可以使用 .catch() 方法处理 Promise 的错误。

异步操作示例:

const fetchData = async () => {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    // 处理数据
  } catch (error) {
    console.error('请求失败:', error);
  }
};

26. 解释 React 的合成事件。

答案:React 的合成事件是 React 自己实现的事件系统,它封装了浏览器的原生事件,提供了一致的 API。合成事件具有跨浏览器的兼容性,可以更好地控制事件的行为。

示例:

const MyComponent = () => {
  const handleClick = (event) => {
    console.log(event); // 合成事件
  };

  return <button onClick={handleClick}>点击我</button>;
};

27. React 中的 PropTypes 是什么?

答案PropTypes 是一个用于类型检查 React 组件 props 的库。它可以帮助开发者确保组件接收到正确类型的 props,增强代码的可维护性。

示例:

import PropTypes from 'prop-types';

const MyComponent = ({ name, age }) => {
  return (
    <div>
      <p>名字: {name}</p>
      <p>年龄: {age}</p>
    </div>
  );
};

MyComponent.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number,
};

28. 如何在 React 中进行单元测试?

答案:可以使用 JestReact Testing Library 进行 React 组件的单元测试。Jest 提供测试框架,而 React Testing Library 提供用于测试组件的工具。

示例:

import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

test('renders name', () => {
  render(<MyComponent name="John" age={30} />);
  const nameElement = screen.getByText(/名字: John/i);
  expect(nameElement).toBeInTheDocument();
});

29. 如何在 React 中实现数据缓存?

答案:可以使用浏览器的本地存储(localStorage 或 sessionStorage)或通过状态管理库(如 Redux)来实现数据缓存。

使用 localStorage 示例:

const MyComponent = () => {
  const [data, setData] = useState(() => {
    return localStorage.getItem('myData') || '';
  });

  useEffect(() => {
    localStorage.setItem('myData', data);
  }, [data]);

  return (
    <input value={data} onChange={(e) => setData(e.target.value)} />
  );
};

30. React 中的 key 属性在列表渲染中的重要性是什么?

答案key 属性在列表渲染中用于标识每个元素的唯一性。它帮助 React 确定哪些元素在更新时需要被修改、添加或删除。使用唯一且稳定的 key 能够提高性能,避免不必要的重渲染。

示例:

const items = ['Apple', 'Banana', 'Cherry'];

const ItemList = () => (
  <ul>
    {items.map((item, index) => (
      <li key={index}>{item}</li> // 应该使用唯一 ID 而非索引
    ))}
  </ul>
);

31. React 中的 useLayoutEffect 是什么?

答案useLayoutEffect 是一个 Hook,和 useEffect 类似,但它在 DOM 更新后、浏览器绘制前执行。适合需要立即读取和同步布局的场景。

示例:

useLayoutEffect(() => {
  // 代码在 DOM 更新后执行
}, [依赖项]);

32. React 中的 useImperativeHandle 是什么?

答案useImperativeHandle 是一个 Hook,允许父组件自定义子组件的实例值。通过 forwardRef 使用时,可以控制子组件暴露给父组件的实例值。

示例:

const FancyInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
  }));

  return <input ref={inputRef} />;
});

// 使用 FancyInput
const Parent = () => {
  const ref = useRef();

  return (
    <>
      <FancyInput ref={ref} />
      <button onClick={() => ref.current.focus()}>聚焦输入框</button>
    </>
  );
};

33. 如何在 React 中执行定时器?

答案:可以使用 setTimeoutsetInterval 来实现定时器。通常在 useEffect 中设置定时器,并在清理函数中清除它们。

示例:

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

  useEffect(() => {
    const timer = setInterval(() => {
      setCount((prevCount) => prevCount + 1);
    }, 1000);

    return () => clearInterval(timer); // 清除定时器
  }, []);

  return <div>计数: {count}</div>;
};

34. React 中的 forwardRef 是什么?

答案forwardRef 是一个高阶组件,用于转发引用到子组件的 DOM 元素。它允许父组件直接访问子组件的 DOM 节点。

示例:

const CustomButton = React.forwardRef((props, ref) => {
  return <button ref={ref}>{props.children}</button>;
});

// 使用 CustomButton
const Parent = () => {
  const ref = useRef();

  return (
    <>
      <CustomButton ref={ref}>点击我</CustomButton>
      <button onClick={() => ref.current.focus()}>聚焦按钮</button>
    </>
  );
};

35. React 中的 React.memo 是什么?

答案React.memo 是一个高阶组件,用于优化函数组件的性能。它通过浅比较 props,决定是否重新渲染组件。适用于不需要频繁更新的组件。

示例:

const MyComponent = React.memo(({ value }) => {
  console.log('组件渲染');
  return <div>{value}</div>;
});

36. 如何在 React 中处理多选框和复选框?

答案:使用受控组件的方式,可以通过设置状态来管理多选框和复选框的值。

示例:

const CheckboxGroup = () => {
  const [selectedValues, setSelectedValues] = useState([]);

  const handleChange = (event) => {
    const value = event.target.value;
    setSelectedValues((prev) =>
      prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value]
    );
  };

  return (
    <div>
      <label>
        <input type="checkbox" value="Option1" onChange={handleChange} />
        Option 1
      </label>
      <label>
        <input type="checkbox" value="Option2" onChange={handleChange} />
        Option 2
      </label>
      <p>选择的值: {selectedValues.join(', ')}</p>
    </div>
  );
};

37. React 中如何处理导航和重定向?

答案:可以使用 react-router-dom 提供的 useHistoryuseNavigate Hook 进行导航和重定向。

示例:

import { useNavigate } from 'react-router-dom';

const MyComponent = () => {
  const navigate = useNavigate();

  const handleClick = () => {
    navigate('/new-path'); // 导航到新路径
  };

  return <button onClick={handleClick}>导航</button>;
};

38. React 中如何实现无状态组件?

答案:无状态组件是指不使用内部状态的组件。可以使用函数组件来实现。

示例:

const StatelessComponent = ({ message }) => {
  return <div>{message}</div>;
};

39. 解释 React 中的服务端渲染(SSR)。

答案:服务端渲染(SSR)是指在服务器上生成完整的 HTML 页面并发送给客户端。与客户端渲染相比,SSR 提供更快的首屏渲染和更好的 SEO 支持。可以使用框架如 Next.js 来实现 React 的 SSR。

40. React 的 useDebugValue Hook 是什么?

答案useDebugValue 是一个用于在 React DevTools 中显示自定义 Hook 调试信息的 Hook。它可以帮助开发者在调试时更好地理解 Hook 的状态。

示例:

function useCustomHook(value) {
  const debugValue = value ? '有值' : '无值';
  useDebugValue(debugValue);
  return value;
}

41. React 中的 useEffect 如何处理清理?

答案useEffect 可以返回一个清理函数,用于在组件卸载或依赖项变化时执行清理操作。这适用于清理订阅、定时器或其他副作用。

示例:

useEffect(() => {
  const timer = setTimeout(() => {
    console.log('定时器触发');
  }, 1000);

  return () => clearTimeout(timer); // 清理定时器
}, []);

42. 如何在 React 中实现上下文(Context)?

答案:通过创建 Context 对象,可以在组件树中共享数据,而无需通过每层的 props。使用 Provider 提供值,使用 ConsumeruseContext 获取值。

示例:

const MyContext = React.createContext();

const MyProvider = ({ children }) => {
  const value = { user: 'John Doe' };
  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
};

const MyComponent = () => {
  const context = useContext(MyContext);
  return <div>用户: {context.user}</div>;
};

43. React 中的 Suspenselazy 的用法是什么?

答案React.lazy 用于动态导入组件,Suspense 用于处理加载状态。使用 React.lazy 进行懒加载时,Suspense 组件可以指定加载时的占位内容。

示例:

const LazyComponent = React.lazy(() => import('./LazyComponent'));

const App = () => (
  <React.Suspense fallback={<div>加载中...</div>}>
    <LazyComponent />
  </React.Suspense>
);

44. React 中的 useRef 有哪些用途?

答案useRef 用于创建可变的引用,主要有以下用途:

  1. 获取 DOM 元素的引用。
  2. 存储任何可变的数据,而不会导致重新渲染。

示例:

const MyComponent = () => {
  const inputRef = useRef();

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <>
      <input ref={inputRef} />
      <button onClick={focusInput}>聚焦输入框</button>
    </>
  );
};

45. React 中的 useMemouseCallback 具体使用场景是什么?

答案

  • useMemo:用于缓存计算结果,避免在每次渲染时重新计算。适合性能密集型计算。

    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
    
  • useCallback:用于缓存函数实例,避免在每次渲染时创建新函数。适合传递给子组件的回调函数。

    const memoizedCallback = useCallback(() => {
      doSomething(a);
    }, [a]);
    

46. 如何在 React 中处理键盘事件?

答案:可以将事件处理程序传递给相应的元素,使用 onKeyDownonKeyPressonKeyUp 处理键盘事件。

示例:

const KeyboardEventComponent = () => {
  const handleKeyDown = (event) => {
    console.log('按键:', event.key);
  };

  return <input onKeyDown={handleKeyDown} placeholder="按下任意键" />;
};

47. React 中的 else 条件渲染如何实现?

答案:可以使用 JavaScript 的条件运算符或逻辑运算符来实现 else 条件渲染。

示例:

const ConditionalRendering = ({ isLoggedIn }) => (
  <div>
    {isLoggedIn ? <p>欢迎回来!</p> : <p>请登录.</p>}
  </div>
);

48. 如何在 React 中处理 API 请求?

答案:可以使用 fetch API 或 axios 来处理 API 请求。通常在 useEffect 中进行数据获取操作。

示例:

const DataFetchingComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch('https://api.example.com/data');
      const result = await response.json();
      setData(result);
      setLoading(false);
    };

    fetchData();
  }, []);

  if (loading) return <div>加载中...</div>;
  return <div>数据: {JSON.stringify(data)}</div>;
};

49. React 中的 prop drilling 是什么?

答案prop drilling 是指在组件树中逐层传递 props,直到到达需要的组件。这种方式可能导致代码难以维护,尤其在组件层次较深时。

示例:

const Grandparent = () => {
  const user = { name: 'John' };
  return <Parent user={user} />;
};

const Parent = ({ user }) => {
  return <Child user={user} />;
};

const Child = ({ user }) => {
  return <p>用户: {user.name}</p>;
};

50. 什么是 React 的 Fragment?有什么用?

答案Fragment 是一个用于包裹多个子元素而不在 DOM 中添加额外节点的组件。它有助于减少不必要的 DOM 层级。

示例:

const MyComponent = () => (
  <React.Fragment>
    <h1>标题</h1>
    <p>内容</p>
  </React.Fragment>
);

51. 什么是 React 的 Redux Toolkit?

答案:Redux Toolkit 是 Redux 官方推荐的工具集,旨在简化 Redux 的使用。它提供了一些便利功能,如简化的 reducer、自动生成的 action creators 和中间件集成。

示例:

import { createSlice, configureStore } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
  },
});

const store = configureStore({
  reducer: { counter: counterSlice.reducer },
});

52. React 中的 useTransition 是什么?

答案useTransition 是一个 Hook,允许在执行状态更新时指定 UI 的过渡效果。它可以帮助处理耗时的状态更新,确保用户界面响应迅速。

示例:

const [isPending, startTransition] = useTransition();

const handleClick = () => {
  startTransition(() => {
    setState(newState);
  });
};

53. 如何在 React 中使用 Service Worker?

答案:使用 Create React App 创建的项目中,Service Worker 可以通过 registerServiceWorker 文件实现。通常用于缓存静态资源和实现离线功能。

示例:

import { register } from './serviceWorker';

register();

54. 如何在 React 中实现国际化(i18n)?

答案:可以使用 react-i18next 或其他国际化库来实现多语言支持。通过上下文和 hooks 进行语言切换和文本翻译。

示例:

import { useTranslation } from 'react-i18next';

const MyComponent = () => {
  const { t } = useTranslation();
  return <h1>{t('welcome_message')}</h1>;
};

55. React 中如何实现自定义 Hook?

答案:自定义 Hook 是一个以 use 开头的函数,可以封装逻辑以在多个组件之间共享。它可以使用其他 Hook 组成。

示例:

const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch(url);
      const result = await response.json();
      setData(result);
      setLoading(false);
    };

    fetchData();
  }, [url]);

  return { data, loading };
};

// 使用自定义 Hook
const DataComponent = () => {
  const { data, loading } = useFetch('https://api.example.com/data');

  if (loading) return <div>加载中...</div>;
  return <div>数据: {JSON.stringify(data)}</div>;
};

2025年面试中常见的 React 问题及答案(续)

继续增加更多常见的 React 面试问题及其答案,以帮助你在求职时更好地准备。

56. 解释 React 中的 useDebugValue Hook 的作用。

答案useDebugValue 是一个用于在 React DevTools 中显示自定义 Hook 调试信息的 Hook。它可以帮助开发者在调试时更好地理解 Hook 的状态,尤其是在使用自定义 Hook 时。

示例:

function useCustomHook(value) {
  const debugValue = value ? '有值' : '无值';
  useDebugValue(debugValue);
  return value;
}

57. 如何在 React 中实现自适应布局?

答案:可以使用 CSS Flexbox 或 Grid 布局来实现自适应布局。结合媒体查询,可以根据屏幕尺寸调整页面元素的样式。

示例:

.container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.item {
  flex: 1 1 auto; /* 自适应 */
  margin: 10px;
}

58. React 中的 useMemo 应用场景是什么?

答案useMemo 主要用于性能优化,尤其是在计算开销较大的值时。它可以防止在每次渲染时重新计算值,仅在依赖项变化时重新计算。

示例:

const MyComponent = ({ a, b }) => {
  const memoizedValue = useMemo(() => {
    return expensiveCalculation(a, b);
  }, [a, b]);

  return <div>计算结果: {memoizedValue}</div>;
};

59. React 中的 useCallback 应用场景是什么?

答案useCallback 用于缓存函数实例,避免在每次渲染时创建新函数。适合传递给子组件的回调函数,从而防止不必要的子组件重新渲染。

示例:

const MyComponent = ({ onClick }) => {
  const handleClick = useCallback(() => {
    onClick();
  }, [onClick]);

  return <button onClick={handleClick}>点击我</button>;
};

60. 如何在 React 中管理组件的样式?

答案:可以通过多种方式管理组件的样式,包括:

  • 内联样式:通过 style 属性直接在组件中定义样式。
  • CSS Modules:使用模块化的 CSS 文件,避免全局命名冲突。
  • Styled Components:使用 CSS-in-JS 库动态定义样式。
  • 传统 CSS 文件:直接引入 CSS 文件。

内联样式示例:

const MyComponent = () => {
  return (
    <div style={{ color: 'blue', fontSize: '20px' }}>
      Hello World
    </div>
  );
};

61. React 中的 React.StrictMode 的作用是什么?

答案React.StrictMode 是一个用于检测应用中的潜在问题的工具。在开发模式下,它会对子组件进行额外的检查,以帮助识别不安全的生命周期方法、过时的 API 使用等。

示例:

<React.StrictMode>
  <App />
</React.StrictMode>

62. 如何在 React 中实现懒加载路由?

答案:可以结合 React.lazySuspense 来实现路由的懒加载。使用 React.lazy 动态导入组件,并用 Suspense 包裹路由。

示例:

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

const App = () => (
  <Router>
    <Suspense fallback={<div>加载中...</div>}>
      <Switch>
        <Route path="/lazy" component={LazyComponent} />
      </Switch>
    </Suspense>
  </Router>
);

63. React 中的条件渲染如何实现?

答案:可以使用 JavaScript 的条件语句(如三元运算符或逻辑与运算符)来实现条件渲染。

示例:

const ConditionalRendering = ({ isLoggedIn }) => (
  <div>
    {isLoggedIn ? <p>欢迎回来!</p> : <p>请登录.</p>}
  </div>
);

64. 在 React 中使用 fetch 进行数据请求的最佳实践有哪些?

答案

  • useEffect 中进行数据请求,确保在组件挂载时触发。
  • 处理错误并更新状态。
  • 在请求完成后清理状态,避免内存泄漏。

示例:

const DataComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://api.example.com/data');
        if (!response.ok) throw new Error('网络错误');
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <div>加载中...</div>;
  if (error) return <div>错误: {error}</div>;
  return <div>数据: {JSON.stringify(data)}</div>;
};

65. React 中的 useImperativeHandle 用于什么场景?

答案useImperativeHandle 允许在使用 forwardRef 时自定义暴露给父组件的实例值。适用于需要控制子组件的行为如焦点、选择等。

示例:

const CustomInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
  }));

  return <input ref={inputRef} {...props} />;
});

// 使用 CustomInput
const App = () => {
  const ref = useRef();

  return (
    <>
      <CustomInput ref={ref} />
      <button onClick={() => ref.current.focus()}>聚焦输入框</button>
    </>
  );
};

66. 如何在 React 中使用 CSS-in-JS?

答案:可以使用 styled-componentsemotion 等库,允许在 JavaScript 中定义样式,并与组件结合使用。

示例(使用 styled-components):

import styled from 'styled-components';

const Button = styled.button`
  background-color: blue;
  color: white;
  padding: 10px;
`;

const MyComponent = () => {
  return <Button>点击我</Button>;
};

67. 如何在 React 中实现音视频播放?

答案:可以使用 HTML5 <audio><video> 标签,并通过 React 的状态和事件处理来控制播放。

示例:

const VideoPlayer = ({ src }) => {
  const videoRef = useRef();

  const handlePlay = () => {
    videoRef.current.play();
  };

  return (
    <div>
      <video ref={videoRef} width="400" controls>
        <source src={src} type="video/mp4" />
        Your browser does not support HTML5 video.
      </video>
      <button onClick={handlePlay}>播放</button>
    </div>
  );
};

68. React 中的 useLayoutEffectuseEffect 有何不同?

答案useLayoutEffect 在 DOM 更新后、浏览器绘制前同步执行,而 useEffect 在浏览器绘制后异步执行。useLayoutEffect 适合需要同步测量 DOM 的场景。

示例:

useLayoutEffect(() => {
  // 读取 DOM 布局
}, [依赖项]);

69. 如何在 React 中实现表单验证?

答案:可以使用状态管理表单输入,并在提交时进行验证。也可以结合第三方库如 Formikreact-hook-form 来简化表单验证逻辑。

示例(简单验证):

const FormComponent = () => {
  const [name, setName] = useState('');
  const [error, setError] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!name) {
      setError('姓名不能为空');
    } else {
      setError('');
      // 提交表单
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      {error && <p>{error}</p>}
      <button type="submit">提交</button>
    </form>
  );
};

70. 如何在 React 中使用 WebSocket 进行实时数据更新?

答案:可以使用 WebSocket API 在组件中建立连接,并在 useEffect 中处理连接的建立和关闭。

示例:

const WebSocketComponent = () => {
  const [messages, setMessages] = useState([]);
  const wsRef = useRef();

  useEffect(() => {
    wsRef.current = new WebSocket('wss://example.com/socket');

    wsRef.current.onmessage = (event) => {
      setMessages((prev) => [...prev, event.data]);
    };

    return () => {
      wsRef.current.close();
    };
  }, []);

  return (
    <div>
      <h2>消息:</h2>
      <ul>
        {messages.map((msg, index) => (
          <li key={index}>{msg}</li>
        ))}
      </ul>
    </div>
  );
};

71. 如何在 React 中处理文件上传?

答案:可以使用 <input type="file"> 元素来实现文件上传,并在 onChange 事件中处理文件选择。

示例:

const FileUpload = () => {
  const handleFileChange = (event) => {
    const file = event.target.files[0];
    console.log('上传文件:', file);
  };

  return (
    <input type="file" onChange={handleFileChange} />
  );
};

72. 如何在 React 中使用 Redux-Saga 处理异步操作?

答案:Redux-Saga 是一个用于处理副作用的中间件,使用生成器函数管理异步操作。可以通过 takeEverytakeLatest 等效果处理异步请求。

示例:

import { call, put, takeEvery } from 'redux-saga/effects';

function* fetchData() {
  try {
    const response = yield call(fetch, 'https://api.example.com/data');
    const data = yield response.json();
    yield put({ type: 'FETCH_SUCCESS', payload: data });
  } catch (error) {
    yield put({ type: 'FETCH_FAIL', payload: error.message });
  }
}

function* watchFetchData() {
  yield takeEvery('FETCH_REQUEST', fetchData);
}

// 在根 Saga 中使用
export default function* rootSaga() {
  yield all([watchFetchData()]);
}

73. React 中的 useTransition 是什么,有何作用?

答案useTransition 是一个 Hook,用于帮助管理状态更新的过渡状态。它允许在状态更新时标记状态为“过渡中”,从而提高用户体验。

示例:

const [isPending, startTransition] = useTransition();

const handleClick = () => {
  startTransition(() => {
    // 更新状态
    setCount(count + 1);
  });
};

74. 如何在 React 中实现分页?

答案:可以使用状态管理当前页码和每页显示的项目数,并通过计算当前页的数据来实现分页。

示例:

const Pagination = ({ items, itemsPerPage }) => {
  const [currentPage, setCurrentPage] = useState(1);
  const totalPages = Math.ceil(items.length / itemsPerPage);

  const handlePageChange = (page) => {
    setCurrentPage(page);
  };

  const displayedItems = items.slice(
    (currentPage - 1) * itemsPerPage,
    currentPage * itemsPerPage
  );

  return (
    <div>
      {displayedItems.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
      <div>
        {Array.from({ length: totalPages }, (_, index) => (
          <button key={index + 1} onClick={() => handlePageChange(index + 1)}>
            {index + 1}
          </button>
        ))}
      </div>
    </div>
  );
};

75. React 中的 useDeferredValue 是什么?

答案useDeferredValue 是一个 Hook,用于延迟更新某个状态,以提高用户体验。它允许组件在输入时保持响应,而不立即更新所有相关状态。

示例:

const SearchComponent = () => {
  const [inputValue, setInputValue] = useState('');
  const deferredInputValue = useDeferredValue(inputValue);

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <p>搜索内容: {deferredInputValue}</p>
    </div>
  );
};

76. 如何在 React 中实现国际化(i18n)?

答案:可以使用 react-i18next 库来实现国际化。它提供了简单的 API 来处理多语言支持和文本翻译。

示例:

import { useTranslation } from 'react-i18next';

const MyComponent = () => {
  const { t } = useTranslation();

  return <h1>{t('welcome_message')}</h1>;
};

77. React 中的 useImperativeHandle 用于什么场景?

答案useImperativeHandle 用于在 forwardRef 中自定义暴露给父组件的实例值,以便父组件可以调用子组件的方法或属性。

示例:

const CustomInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
  }));

  return <input ref={inputRef} {...props} />;
});

// 使用 CustomInput
const App = () => {
  const ref = useRef();

  return (
    <>
      <CustomInput ref={ref} />
      <button onClick={() => ref.current.focus()}>聚焦输入框</button>
    </>
  );
};

78. 如何在 React 中实现自定义 Hooks?

答案:自定义 Hook 是以 use 开头的函数,可以封装逻辑以在多个组件之间共享。它可以使用其他 Hook 组合而成。

示例:

const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch(url);
      const result = await response.json();
      setData(result);
      setLoading(false);
    };

    fetchData();
  }, [url]);

  return { data, loading };
};

// 使用自定义 Hook
const DataComponent = () => {
  const { data, loading } = useFetch('https://api.example.com/data');

  if (loading) return <div>加载中...</div>;
  return <div>数据: {JSON.stringify(data)}</div>;
};

79. React 中如何实现状态提升?

答案:状态提升是指将多个组件共享的状态提升到它们的共同父组件中,以便父组件可以管理和传递状态。

示例:

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

  return (
    <div>
      <ChildComponent count={count} setCount={setCount} />
      <p>父组件的计数: {count}</p>
    </div>
  );
};

const ChildComponent = ({ count, setCount }) => {
  return (
    <button onClick={() => setCount(count + 1)}>增加</button>
  );
};

80. React 中的 useEffect 依赖项数组的作用是什么?

答案useEffect 的依赖项数组用于控制副作用的执行时机。当依赖项数组中的值发生变化时,useEffect 会重新执行。如果传递一个空数组,useEffect 只在组件挂载时执行一次。

示例:

useEffect(() => {
  console.log('组件挂载或依赖项变化时执行');
}, [dependency]); // 只有当 dependency 变化时才会重新执行

81. 如何在 React 中处理多语言支持?

答案:可以使用第三方库如 react-i18next 来处理多语言支持。它提供了简单的 API 来加载和切换语言。

示例:

import { useTranslation } from 'react-i18next';

const App = () => {
  const { t, i18n } = useTranslation();

  const changeLanguage = (lng) => {
    i18n.changeLanguage(lng);
  };

  return (
    <div>
      <h1>{t('welcome_message')}</h1>
      <button onClick={() => changeLanguage('en')}>英语</button>
      <button onClick={() => changeLanguage('fr')}>法语</button>
    </div>
  );
};

82. React 中的 React.memo 是什么?

答案React.memo 是一个高阶组件,用于优化函数组件的性能。它通过浅比较 props,决定是否重新渲染组件。

示例:

const MyComponent = React.memo(({ value }) => {
  console.log('组件渲染');
  return <div>{value}</div>;
});

83. 如何在 React 中实现主题切换?

答案:可以使用 Context API 和状态管理来实现主题切换。通过在上下文中存储当前主题,子组件可以根据主题进行样式调整。

示例:

const ThemeContext = React.createContext();

const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme((prev) => (prev === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

const ThemedComponent = () => {
  const { theme, toggleTheme } = useContext(ThemeContext);
  return (
    <div className={theme}>
      <p>当前主题: {theme}</p>
      <button onClick={toggleTheme}>切换主题</button>
    </div>
  );
};

84. React 中的 useReducer 适用于什么场景?

答案useReducer 适用于管理复杂状态逻辑的场景,特别是当状态依赖于先前状态时。可以将其视为 useState 的替代方案,特别是在处理多个子值或状态变化复杂时。

示例:

const initialState = { count: 0 };

const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
};

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

  return (
    <div>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>增加</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>减少</button>
    </div>
  );
};

85. React 中的 React.StrictMode 的作用是什么?

答案React.StrictMode 是一个用于检测应用中的潜在问题的工具。在开发模式下,它会对子组件进行额外的检查,以帮助识别不安全的生命周期方法、过时的 API 使用等。

示例:

<React.StrictMode>
  <App />
</React.StrictMode>

86. React 中如何处理组件的状态管理?

答案:组件的状态可以通过 useState Hook 管理。对于复杂状态,可以使用 useReducer 或结合第三方状态管理库,如 Redux 或 MobX。

示例(使用 useState):

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

  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={() => setCount(count + 1)}>增加</button>
    </div>
  );
};

87. React 中的 useCallback 的作用是什么?

答案useCallback 用于缓存函数实例,避免在每次渲染时创建新函数。适合传递给子组件的回调函数,从而防止不必要的子组件重新渲染。

示例:

const MyComponent = ({ onClick }) => {
  const handleClick = useCallback(() => {
    onClick();
  }, [onClick]);

  return <button onClick={handleClick}>点击我</button>;
};

88. 如何在 React 中实现错误边界?

答案:可以通过创建一个类组件并实现 componentDidCatchgetDerivedStateFromError 方法来实现错误边界。它用于捕获子组件中的错误并显示备用 UI。

示例:

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    console.error('捕获到错误:', error, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>出错了!</h1>;
    }

    return this.props.children;
  }
}

// 使用错误边界
<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

89. React 中的 useLayoutEffectuseEffect 有何区别?

答案useLayoutEffect 在 DOM 更新后、浏览器绘制前同步执行,而 useEffect 在浏览器绘制后异步执行。useLayoutEffect 适合需要同步测量 DOM 的场景。

示例:

useLayoutEffect(() => {
  // 读取 DOM 布局
}, [依赖项]);

90. React 中如何处理组件的生命周期?

答案:可以使用类组件的生命周期方法(如 componentDidMountcomponentDidUpdatecomponentWillUnmount)或使用 useEffect Hook 来管理函数组件的生命周期。

示例(类组件):

class MyComponent extends React.Component {
  componentDidMount() {
    console.log('组件已挂载');
  }

  componentWillUnmount() {
    console.log('组件将卸载');
  }

  render() {
    return <div>Hello World</div>;
  }
}

示例(函数组件):

const MyComponent = () => {
  useEffect(() => {
    console.log('组件已挂载');
    return () => {
      console.log('组件将卸载');
    };
  }, []);

  return <div>Hello World</div>;
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,928评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,748评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,282评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,065评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,101评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,855评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,521评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,414评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,931评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,053评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,191评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,873评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,529评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,074评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,188评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,491评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,173评论 2 357

推荐阅读更多精彩内容