浮头导航网

专注编程技术分享的开发者社区

2025前端面试题-React基础篇_react前端项目

以下为React面试基础考察点总结,具体知识点不会太详细,主要梳理面试核心考察点,为面试做准备。

  • 2025前端面试题-React进阶篇
  • 2025前端面试题-React高阶篇
  • 2025前端面试题-Vue3基础篇
  • 2025前端面试题-Vue3进阶篇

一、基础概念

C 1.React核心设计思想

组件化设计

  • 原子化构建UI 分解为独立的功能单元(如函数式组件/类组件)
  • 组合模式 :通过 props 嵌套实现组件树结构
  • 隔离型 :每个组件维护自身状态和样式( CSS #技术分享-in-JS 生态支持)
  • 复用机制 :高阶组件( HOC )与自定义 Hooks 实现逻辑复用

声明式编程范式

  • 状态驱动UI=f(state) 的数学表达式(无需手动操作DOM)
  • 抽象渲染 :开发者专注描述目标状态,框架处理渲染细节
  • 幂等性保证 :相同 state 必定输出相同视图(确定性原则)

高效更新引擎

  • 虚拟DOM层 :内存中轻量级 DOM 表示(对象树结构)
  • Diff算法优化 :启发式 O(n) 复杂度比较策略(基于树遍历策略)
  • 批量更新策略 :自动合并 setState 操作(异步更新策略)
  • 渲染流水线Fiber 架构实现可中断渲染(并发模式)

单向数据控制

  • 严格数据通道props 自上而下传递(严禁子级逆向修改)
  • 状态托管 :通过 Context/Redux 实现跨层级通信
  • 副作用隔离Hooks 机制约束副作用边界( useEffect 依赖链)

这些原则使 React 具备:高维护性 (组件解耦)、高性能 (智能更新)、可预测性 (数据流透明)。

JavaScript 2.JSX

1.JSX的本质

  • 定义JSX(JavaScript XML) 是React提供的语法扩展,允许在JavaScript中编写类似HTML的结构
  • 核心作用 :提升代码可读性,直观描述UI的层次结构,同时保留JavaScript的全部编程能力
  • 底层实现 :JSX会被Babel或TypeScript编译器转换为 React.createElement() 调用,生成React元素(即虚拟DOM对象)
const element = <div className="title">Hello React</div>;

const element = React.createElement( 'div', { className:'title' }, 'Hello React' )

2.JSX编译过程

  • 编译阶段 :Babel的 @babel/plugin-transform-react-jsx 插件负责转换
  • 新转换模式 (React17+):通过 jsx-runtime 自动引入 _jsx 函数,无需手动引入React
import { jsx as _jsx } from 'react/jsx-runtime';
const element = _jsx('div', { className: 'title', children: 'Hello React' });

3.JSX与HTML的关键区别

  • 属性命名 :使用小驼峰命名(如 className,htmlFor,onClick
  • 样式对象 :CSS属性转为小驼峰,值为字符串或数值
<div style={{ fontSize: 14, padding: '10px' }} ></div>
  • 布尔值属性 :属性省略值时默认为 true (如 <input disabled />
  • 子元素类型 :支持字符串、JSX元素、数组, false/null/undefined 不渲染

4.JSX中的表达式嵌入

  • 动态内容 :使用{}嵌入任意JavaScript表达式
<h1>当前时间:{new Date().toLocaleTimeString()}</h1>
  • 条件渲染
{isLoggedIn ? <UserPanel /> : <LoginButton />}
  • 列表渲染
<ul>

{items.map(item => ( <li key={item.id}>{item.name}</li>

))} </ul>

5.JSX安全特性

  • 自动转义 :嵌入内容(如用户输入)会被转义为字符串,防止XSS攻击
const userInput = '<script>恶意代码</script>';
<div>{userInput}</div>
  • dangerouslySetInnerHTML :显式插入原始HTML(需手动防范风险)
<div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />

6.JSX高级用法

  • 片段 (Fragment):包裹多个元素避免额外的DOM节点
<React.Fragment>

<td>Column 1</td>

<td>Column 2</td>

</React.Fragment>
  • 组件嵌套 :自定义组件必须以大写字母开头,小写标签视为原生标签
<MyComponent prop1="value">

<ChildComponent />

</MyComponent>

7.JSX与模版引擎对比

| 特性 | JSX | 传统模板引擎(如 Vue) | | ---

| 语法灵活性 | 原生 JavaScript 能力,无 DSL 限制 | 受限于模板语法(指令、过滤器等) | | 组件逻辑 | 逻辑与 UI 紧密耦合 | 分离的模板与脚本块 | | 类型安全 | 完美支持 TypeScript 类型检查 | 需要额外工具支持 |

8.实战技巧

  • 条件渲染优化 :使用短路运算简化简单条件
{isLoading && <Spinner />}
  • 动态组件 :通过变量名渲染不同组件
const components = { photo: PhotoComponent, video: VideoComponent };
const DynamicComponent = components[type];
return <DynamicComponent />;

高频面试题

1.为什么JSX中组件首字母必须大写?

  • React通过首字母大小写区分原生DOM标签(如 <div> )和自定义组件(如 <MyComponent>

2.如何避免JSX回调中的闭包陷阱?

  • 使用 useCallback 缓存函数,或通过函数参数传递最新值

3.生命周期方法演进

1.类组件生命周期演进

1.传统生命周期(React 16.3前)

class Example extends React.Component {

  constructor(props) {
    super(props);
    this.state = {  };
  }

componentWillMount() { } render() { return <div>...</div> } componentDidMount() { }

componentWillReceiveProps(nextProps) { } shouldComponentUpdate(nextProps, nextState) { return true } componentWillUpdate() { } render() { } componentDidUpdate(prevProps, prevState) { }

componentWillUnmount() { } }

4.新版本生命周期(React 16.3+)

class Example extends React.Component {

  static getDerivedStateFromProps(props, state) {

  }

componentDidCatch(error, info) { }

getSnapshotBeforeUpdate(prevProps, prevState) { } }

2.生命周期阶段

1.Mounting阶段

  • constructor :初始化state、绑定方法
  • getDerivedStateFromProps :props初始化时同步到state
  • render :生成虚拟DOM
  • componentDidMount :网络请求、DOM操作、订阅事件

2.Updating阶段

  • getDerviedStateFromProps :props变化时更新state
  • shouldComponentUpdate :返回false可阻止渲染(性能优化核心)
  • render :生成新虚拟DOM
  • getSnapshotBeforeUpdate :获取DOM更新前的状态(如滚动位置)
  • componentDidUpdate :DOM更新后操作、网络请求

3.Unmounting阶段

  • componentWillUnmount :清除定时器、取消订阅、释放资源等

3.函数组件生命周期模拟

通过 useEffect Hook 实现生命周期控制:

function Example() {

  useEffect(() => {

    const timer = setInterval(...);

    return () => {
      clearInterval(timer);
    }
  }, []);

useEffect(() => { });

useEffect(() => { }, [count]);

const [derivedState, setDerivedState] = useState(); useEffect(() => { setDerivedState(props.input); }, [props.input]); }

4.生命周期废弃原因与最佳实践

| 废弃方法 | 替代方案 | 废弃原因 | | ---

| componentWillMount | constructor 或 useEffect | 异步渲染导致可能多次执行 | | componentWillReceiveProps | getDerivedStateFromProps +

| componentWillUpdate | getSnapshotBeforeUpdate | 不安全副作用操作风险 |

5.性能优化

  • shouldComponentUpdate优化
shouldComponentUpdate(nextProps, nextState) {

  return !shallowEqual(this.props, nextProps)
      || !shallowEqual(this.state, nextState);
}
  • PureComponent自动浅比较
class Example extends React.PureComponent { ... }
  • React.memo函数组件优化
const MemoComponent = React.memo(MyComponent, areEqual);

6.错误边界处理

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

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

componentDidCatch(error, info) { logErrorToService(error, info); }

render() { return this.state.hasError ? <FallbackUI />

: this.props.children; } }

7.高频面试题

1.为什么componentWillXXX系列方法被标记为UNSAFE

  • 异步渲染模式(Concurrent Mode)下可能被多次调用
  • 副作用操作可能会导致渲染不一致

2.useEffect与生命周期方法的对应关系

  • useEffect(fn, []) -> componentDidMount + componentWillUnmount
  • useEffect(fn) -> componentDidUpdate
  • useEffect(fn, [dep]) -> 特定依赖更新时的副作用

3.getDerivedStateFromProps的正确使用场景

  • 仅当需要根据props变化被动更新state时使用
  • 避免在此方法中触发副作用

4.受控组件与非受控组件

1.核心定义

| 组件类型 | 数据管理方式 | 控制权 | | ---

| 受控组件 (Controlled) | 表单数据由 React 组件状态(state)驱动 | React 完全控制 | | 非受控组件 (Uncontrolled) | 表单数据由 DOM 节点自身维护 | DOM 原生控制 |

2.实现原理对比

1.受控组件实现

function ControlledForm() {
  const [value, setValue] = useState('');

const handleSubmit = (e) => { e.preventDefault(); console.log('提交值:', value); };

return ( <form onSubmit={handleSubmit}>

<input type="text" value={value} onChange={(e) => setValue(e.target.value)} />

<button type="submit">提交</button>

</form>

); }

核心特点

  • value绑定到React state
  • onChange同步更新state
  • 数据流: React state -> DOM 显示

2.非受控组件实现

function UncontrolledForm() {
  const inputRef = useRef(null);

const handleSubmit = (e) => { e.preventDefault(); console.log('提交值:', inputRef.current.value); };

return ( <form onSubmit={handleSubmit}>

<input type="text" defaultValue="初始值" ref={inputRef} />

<button type="submit">提交</button>

</form>

); }

核心特点

  • 使用ref访问DOM节点值
  • defaultValue设置初始值(非动态更新)
  • 数据流:DOM节点 -> 手动获取值

3.核心差异分析

| 维度 | 受控组件 | 非受控组件 | | ---

| 数据存储位置 | React 组件状态 | DOM 节点 | | 值更新机制 | 通过 onChange 事件同步更新 state | 用户输入直接修改 DOM,需手动获取 | | 表单验证时机 | 实时验证(每次输入触发) | 提交时验证 | | 动态表单控制 | 支持动态禁用/启用字段 | 需要手动操作 DOM | | 性能影响 | 高频输入场景可能引发多次渲染 | 无额外渲染开销 | | 文件上传支持 | 不支持(文件输入天生不可控) | 必须使用 |

4.最佳实践场景

受控组件适用场景

  1. 实时表单验证(如密码强度提示)
  2. 条件禁用提交按钮
  3. 动态表单字段(根据输入增减表单项)
  4. 复杂表单联动(多个输入相互依赖)

非受控组件适用场景

  1. 一次性表单提交(只需要最终值)
  2. 文件上传 <input type="file">
  3. 第三方库集成(需要直接操作DOM)

5.进阶

1.为什么文件输入必须用非受控组件?

<input type="file" onChange={handleFile} />
  • 浏览安全限制 :JavaScript无法以编程方式设置文件输入的值
  • 只读属性 :文件路径由用户选择,无法通过React state控制

2.如何给非受控组件设置初始值?

  • 使用 defaultValue/defaultChecked 属性(类似原生HTML)
<input type="text" defaultValue="初始值" ref={inputRef} />

3.受控组件性能优化策略

  • 防抖处理 (避免高频触发渲染)
const debouncedSetValue = useMemo(() =>

_.debounce(setValue, 300), [] ); <input onChange={e => debouncedSetValue(e.target.value)} />
  • 精细化渲染控制 :使用React.memo隔离表单组件

6.混用模式

function HybridInput({ value: propValue, onChange }) {
  const [internalValue, setInternalValue] = useState(propValue);
  const ref = useRef();

useEffect(() => { if (ref.current.value !== propValue) { ref.current.value = propValue; setInternalValue(propValue); } }, [propValue]);

const handleChange = (e) => { setInternalValue(e.target.value); onChange?.(e.target.value); };

return <input ref={ref} value={internalValue} onChange={handleChange} />; }

7.高频面试题

1.如何避免受控组件的value变成undefined?

  • 确保value的值始终为受控值(字符串/数字),避免null或undefined

2.受控组件中如何实现文本域(textarea)的换行符保留

  • 使用 value={ text.replace(/\n/g, '\\n') } 处理,展示时转换回 \n

3.为什么非受控组件不需要onChange处理?

  • 非受控组件的数据流是单向的(DOM -> React),仅在需要时通过ref获取值

8.决策流程图

是否需要实时验证/控制? → 是 → 使用受控组件
           ↓
          否
           ↓
是否涉及文件上传? → 是 → 使用非受控组件
           ↓
          否
           ↓
是否性能要求极高? → 是 → 使用非受控组件
           ↓
          否
           ↓
默认推荐 → 受控组件

5.类组件和函数式组件

1.核心定义与语法对比

| 维度 | 类组件 | 函数式组件 | | ---

| 定义方式 | ES6 类继承 React.Component | JavaScript 函数 | | 状态管理 | this.state +

| 生命周期 | 完整生命周期方法(如 componentDidMount) | useEffect 模拟生命周期 | | 副作用处理 | 生命周期方法(如 componentDidUpdate) | useEffect +

| 代码量 | 较冗长(需处理 this 绑定) | 更简洁 |

2.生命周期与Hooks映射关系

类组件生命周期方法

class Example extends React.Component {
  componentDidMount() {  }
  componentDidUpdate() {  }
  componentWillUnmount() {  }
  shouldComponentUpdate() {  }
}

函数式组件等效实现

function Example() {

  useEffect(() => {

    return () => {  };
  }, []);

useEffect(() => { });

const memoizedComponent = React.memo(() => (), (prevProps, nextProps) => { return shallowEqual(prevProps, nextProps); }); }

3.状态管理对比

类组件状态管理

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

increment = () => { this.setState(prev => ({ count: prev.count + 1 })); }; }

函数式组件状态管理

function Counter() {
  const [count, setCount] = useState(0);
  const increment = useCallback(() => {
    setCount(prev => prev + 1);
  }, []);
}

4.性能优化策略

| 优化手段 | 类组件 | 函数式组件 | | ---

| 浅比较控制渲染 | PureComponent 或 shouldComponentUpdate | React.memo +

| 计算缓存 | 手动缓存计算结果 | useMemo | | 函数引用稳定性 | 箭头函数或 bind | useCallback | | 渲染节流 | 手动实现防抖/节流 | useDebounce 自定义 Hook |

5.代码组织与逻辑复用

类组件复用

  • 高阶组件(HOC)
const withLogger = WrappedComponent => {
    return class extend React.Component {
        componentDidMount(){
            console.log('component mounted');
        }
        render() {
            return <WrappedComponent {...this.props} />

} } }

函数式组件复用方式

  • 自定义Hooks
const useLogger = () => {
  useEffect(() => {
    console.log('Component mounted');
  }, []);
};

function MyComponent() { useLogger(); return <div>...</div>; }

6.关键差异深度解析

1.this绑定问题(类组件)

class Button extends React.Component {
  handleClick() {
    console.log(this);
  }

}

2.闭包陷阱(函数式组件)

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

useEffect(() => { const timer = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(timer); }, []);

useEffect(() => { const timer = setInterval(() => { setCount(prev => prev + 1); }, 1000); return () => clearInterval(timer); }, []); }

7.现代React开发趋势

1.Hooks的统治地位

  • 官方推荐 函数式组件+Hooks 作为主要开发模式
  • React18新特性(如并发模式)优先支持Hooks

2.类组件使用场景

  • 旧项目维护
  • 需要 Error Boundaries (函数式组件暂不支持)
class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  componentDidCatch(error, info) {  }
  render() {  }
}

8.高频面试题

1.为什么推荐使用函数式组件?

  • 代码简洁 :避免this绑定和类语法冗余
  • 逻辑复用 :自定义Hooks比HOC更灵活
  • 性能优化 :Hooks提供更细颗粒度的控制(如useMemo)
  • 未来兼容 :新特性(如并发模式)优先支持Hooks

2.如何选择组件类型?

  • 新项目:100%函数式组件+Hooks
  • 旧项目:逐步迁移至函数式组件
  • 特殊需求:需要getSnapshotBeforeUpdate或componentDidCatch时使用类组件

3.Hooks的限制和突破

  • 规则:只能在函数顶层调用Hooks
  • 原理:依赖调用顺序的链表结构记录状态
  • 解决方案:使用eslint-plugin-react-hooks强制规范

9.核心对比表

| 维度 | 类组件优势 | 函数式组件优势 | | ---

| 代码可读性 | 生命周期逻辑集中 | 逻辑按功能聚合(Hooks 分组) | | 学习曲线 | 需掌握 OOP 概念 | 纯函数思维更符合 JavaScript 习惯 | | TypeScript 支持 | 类型推断较复杂 | 类型推导更直观 | | 测试友好度 | 需处理实例方法 | 纯函数更易单元测试 | | 未来维护性 | 官方逐步弱化支持 | 新特性优先适配 |

6.props和state

1.核心定义对比

| 维度 | props | state | | ---

| 数据来源 | 外部传入(父组件 → 子组件) | 组件内部维护 | | 可变性 | 只读(Immutable) | 可修改(通过 setState 或 useState) | | 作用范围 | 跨组件层级传递 | 组件私有,外部不可访问 | | 更新触发 | 父组件重新渲染时传递新 props | 调用状态更新方法触发重新渲染 |

2.使用场景

1.何时用props?

  • 组件通信 :父组件向子组件传递数据或回调函数
<UserProfile name="Alice" age={25} onUpdate={handleUpdate} />

function UserProfile({ name, age, onUpdate }) { ... }
  • 配置参数 :定义数组的默认行为或样式
<Button type="primary" size="large" />
  • 渲染控制 :通过props条件性渲染子组件
<Modal visible={showModal} />

2.何时用state

  • 用户交互时 :表单输入、按钮点击等
const [inputValue, setInputValue] = useState('');
  • 组件私有数据 :计时器ID、动画状态等
const [timeId, setTimeId] = useState(null);
  • 动态UI状态 :下拉菜单展开/收起、加载状态
const [isOpen, setIsOpen] = useState(false);

3.深度对比与交互

1.数据流方向

  • 单项数据流 :props只能自上而下传递,state仅在组件内部流动
父组件 → props → 子组件
子组件 → 回调函数 → 父组件更新 state → 传递新 props

2.更新机制对比

| 更新方式 | props | state | | ---

| 类组件 | 父组件重新渲染时自动更新 | this.setState() 触发异步更新 | | 函数组件 | 父组件重新渲染时自动更新 | useState 的 setter 函数触发更新 | | 更新影响 | 子组件接收新 props 后重新渲染 | 当前组件及其子组件重新渲染 |

3.数据交互示例

function Parent() {
  const [count, setCount] = useState(0);
  return <Child count={count} onIncrement={() => setCount(c => c +

}

function Child({ count, onIncrement }) { return ( <div>

<span>{count}</span>

<button onClick={onIncrement}>+</button>

</div>

); }

4.高级使用模式

1.状态提升

当多个组件需要共享状态的时候,将 state 提升到最近的共同祖先

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

<Header theme={theme} />

<Content theme={theme} onToggle={() => setTheme(t => t === 'light' ? 'dark' : 'light')} />

</>

); }

2.受控组件

表单的值由 props 或 state 控制

<input
  value={inputValue}
  onChange={(e) => setInputValue(e.target.value)}
/>

3.非受控组件

使用 ref 直接访问 DOM 节点值(避免与 state 发生冲突)

const inputRef = useRef();

const handleSubmit = () => console.log(inputRef.current.value); return <input ref={inputRef} defaultValue="" />;

5.开发注意事项

1.props不可变性原则

  • 禁止修改props
function User({ user }) {
  user.name = 'Bob';
  return <div>{user.name}</div>;
}

2.state更新陷阱

  • 异步更新问题
setCount(count +

setCount(count + 1);

setCount(prev => prev +

setCount(prev => prev + 1);

3.性能优化

  • 避免不必要的渲染
const MemoComponent = React.memo(MyComponent);

shouldComponentUpdate(nextProps, nextState) { return !shallowEqual(this.props, nextProps); }

六、高频面试题

1.能否在子组件修改props?

  • 不能 。props是只读的,修改会导致React抛出警告。若需要修改数据,应通过父组件传递回调函数更新父级state

2.props和state可以相互转换吗?

  • 可以 ,例如父组件的state作为props传递给子组件,或子组件通过回调函数触发父组件更新

3.如何实现跨多层组件传递props

  • 使用 Context API 或状态管理库(如 Redux、Mobx )避免props逐层传递

以上是React面试题的基础篇内容,如有错误欢迎评论区指正,后续还会更新React进阶篇。

  • 2025前端面试题-React进阶篇
  • 2025前端面试题-React高阶篇
  • 2025前端面试题-Vue3基础篇
  • 2025前端面试题-Vue3进阶篇
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言