返回首页

state 和 props 有什么区别?

问题解析(面试官考察点)

面试官通过此问题主要考察:

  • 对 React 数据流的理解
  • 组件状态管理的掌握程度
  • 是否理解数据传递的机制
  • 能否正确选择使用 state 还是 props

核心概念(基础知识点)

state(状态)

state 是组件内部维护的数据状态,决定了组件的显示形态:

  • 一般在 constructor 中初始化
  • 通过 setState 方法修改
  • 修改后会触发组件重新渲染

props(属性)

props 是从外部传入组件的数据:

  • 父组件向子组件传递数据的主要方式
  • 在组件内部是只读的(不可修改)
  • 可以传递字符串、数字、对象、数组、回调函数等

详细解答(代码示例)

state 的使用示例

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

  updateCount() {
    this.setState((prevState, props) => {
      return { count: prevState.count + 1 };
    });
  }

  render() {
    return (
      <button onClick={() => this.updateCount()}>
        Clicked {this.state.count} times
      </button>
    );
  }
}

setState 的回调函数

this.setState(
  {
    name: "JS每日一题",
  },
  () => console.log("setState finished")
);

第二个参数是一个函数,会在 setState 调用完成并且组件开始重新渲染时被调用。

props 的使用示例

class Welcome extends React.Component {
  render() {
    return <h1>Hello {this.props.name}</h1>;
  }
}

// 使用组件时传递 props
const element = <Welcome name="Sara" onNameChanged={this.handleName} />;

函数组件中的 props

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// 解构写法
function Welcome({ name, age }) {
  return <h1>Hello, {name}, you are {age} years old</h1>;
}

深入理解(原理剖析)

state 和 props 的相同点

  1. 都是 JavaScript 对象
  2. 都用于保存信息
  3. 都能触发渲染更新

state 和 props 的区别

特性 state props
数据来源 组件内部管理 外部传入(父组件)
可修改性 可以在组件内部修改 只读,不可修改
初始化位置 一般在 constructor 中初始化 由父组件传递
作用域 组件内部 父子组件间通信
更新方式 通过 setState 更新 父组件重新渲染时更新

setState 的深入理解

异步更新

this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 可能还是旧值

setState 是异步的,如果需要获取更新后的值:

this.setState({ count: this.state.count + 1 }, () => {
  console.log(this.state.count); // 新值
});

批量更新

React 会将多个 setState 调用合并为一个更新:

// 错误的计数方式
handleClick = () => {
  this.setState({ count: this.state.count + 1 });
  this.setState({ count: this.state.count + 1 });
  this.setState({ count: this.state.count + 1 });
  // 结果只增加了 1,因为 this.state.count 还是旧值
};

// 正确的计数方式
handleClick = () => {
  this.setState((prevState) => ({ count: prevState.count + 1 }));
  this.setState((prevState) => ({ count: prevState.count + 1 }));
  this.setState((prevState) => ({ count: prevState.count + 1 }));
  // 结果增加了 3
};

props 的只读性

// 错误的做法
this.props.name = 'new name'; // 不会生效,且会报错(严格模式下)

// 正确的做法
// 如果需要修改,应该由父组件传递新的 props

props 的只读性保证了组件的纯净性,使组件更容易预测和测试。

最佳实践

何时使用 state

  1. 组件内部需要管理的数据

    • 表单输入值
    • 开关状态
    • 计数器数值
  2. 不需要持久化的临时状态

    • 加载状态
    • 错误信息

何时使用 props

  1. 父子组件通信

    • 父组件向子组件传递数据
    • 父组件向子组件传递回调函数
  2. 配置化组件

    • 通过 props 控制组件外观和行为

状态提升(Lifting State Up)

当多个组件需要共享状态时,将状态提升到它们的最近公共父组件:

// 父组件
class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = { temperature: '', scale: 'c' };
  }

  handleCelsiusChange = (temperature) => {
    this.setState({ scale: 'c', temperature });
  };

  handleFahrenheitChange = (temperature) => {
    this.setState({ scale: 'f', temperature });
  };

  render() {
    const scale = this.state.scale;
    const temperature = this.state.temperature;
    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange} />
        <TemperatureInput
          scale="f"
          temperature={fahrenheit}
          onTemperatureChange={this.handleFahrenheitChange} />
      </div>
    );
  }
}

函数组件中的状态管理(Hooks)

import React, { useState } from 'react';

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

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

面试要点

  1. 数据流向

    • 单向数据流:props 从父到子,state 在组件内部管理
    • 数据自顶向下流动
  2. setState 的注意事项

    • 不要直接修改 state:this.state.count = 1 是错误的
    • setState 可能是异步的
    • 使用函数式更新避免闭包问题
  3. props 的只读性

    • 组件不能修改自己的 props
    • 如果需要修改,应该由父组件传递新的 props
  4. 常见面试题

    • props 和 state 的区别?
    • 为什么 setState 是异步的?
    • 如何正确使用 setState?
    • 什么是状态提升?
  5. 进阶话题

    • 不可变数据的重要性
    • 纯函数组件的优势
    • React 18 中的自动批处理(Automatic Batching)