React状态更新踩坑记:我是这样优雅修改参数的

大家好,我是小杨,一名有6年经验的前端开发工程师。在React开发中,状态(State)和参数(Props)的修改是最基础但也最容易踩坑的部分。今天我就来分享几种常见的React参数修改方法,以及我在项目中总结的最佳实践,避免大家走弯路。


1. 直接修改State?大忌!

新手常犯的一个错误是直接修改state,比如:

jsx 复制代码
// ❌ 错误示范:直接修改state
this.state.count = 10;  

React的state不可变(Immutable) 的,直接修改不会触发重新渲染。正确的做法是使用setState(类组件)或useState的更新函数(函数组件)。


2. 类组件:setState的正确姿势

在类组件里,修改状态必须用setState

jsx 复制代码
class Counter extends React.Component {
  state = { count: 0 };

  increment = () => {
    // ✅ 正确方式:使用setState
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return <button onClick={this.increment}>Count: {this.state.count}</button>;
  }
}

注意setState异步的,如果依赖前一个状态,应该用函数式更新:

jsx 复制代码
this.setState((prevState) => ({ count: prevState.count + 1 }));

3. 函数组件:useState + 不可变更新

在函数组件里,我们使用useState,同样要遵循不可变原则:

jsx 复制代码
import { useState } from 'react';

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

  const increment = () => {
    // ✅ 正确方式:使用useState的更新函数
    setCount(count + 1);
  };

  return <button onClick={increment}>Count: {count}</button>;
}

如果新状态依赖旧状态,推荐使用函数式更新:

jsx 复制代码
setCount((prevCount) => prevCount + 1);

4. 修改对象或数组:避免引用突变

React要求状态更新必须是不可变的,所以直接修改对象或数组的属性是不行的:

jsx 复制代码
const [user, setUser] = useState({ name: 'Alice', age: 25 });

// ❌ 错误:直接修改对象
user.age = 26;  
setUser(user); // 不会触发更新!

// ✅ 正确:创建新对象
setUser({ ...user, age: 26 });

数组的更新也要遵循不可变原则:

jsx 复制代码
const [todos, setTodos] = useState(['Learn React', 'Write Blog']);

// ✅ 正确:使用展开运算符或map/filter
setTodos([...todos, 'New Task']); // 添加
setTodos(todos.filter((todo) => todo !== 'Learn React')); // 删除

5. 性能优化:useState vs useReducer

如果状态逻辑较复杂,useState可能会变得臃肿,这时可以用useReducer

jsx 复制代码
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:
      throw new Error('Unknown action');
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </div>
  );
}

useReducer适合管理复杂状态逻辑,比如表单、全局状态等。


6. 常见坑点 & 解决方案

① 连续setState不会立即更新

jsx 复制代码
// ❌ 连续调用setState,count只会+1
setCount(count + 1);
setCount(count + 1);

// ✅ 使用函数式更新
setCount(prev => prev + 1);
setCount(prev => prev + 1); // 现在会+2

② useEffect依赖问题

如果useEffect依赖state,但忘记加进依赖数组,可能导致闭包问题:

jsx 复制代码
useEffect(() => {
  console.log(count); // 可能拿到旧值
}, []); // ❌ 缺少依赖

useEffect(() => {
  console.log(count); // ✅ 正确
}, [count]); // 依赖正确

总结

  • 不要直接修改state,使用setStateuseState的更新函数
  • 对象/数组更新时,创建新引用
  • 复杂状态逻辑用useReducer
  • 连续更新用函数式setState
  • useEffect依赖要写全

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
超哥--6 小时前
B站视频内容智能分析系统(九):React 前端与管理面板
前端·react.js·前端框架
Cutecat_9 小时前
视频字幕处理工具横向:提取模式 vs 编辑模式,该如何选择
android·前端·ios·语音识别
dsyyyyy11019 小时前
JavaScript变量
开发语言·javascript·ecmascript
qq_422152579 小时前
PDF 加水印工具怎么选?2026 年文档版权保护方案对比
前端·pdf·github
kyriewen10 小时前
手写 Promise.all、race、any:不到 30 行代码,解决并发异步的所有姿势
前端·javascript·面试
brucelee18611 小时前
OpenClaw 浏览器控制(Chrome MCP)完整教程
前端·chrome
ct97811 小时前
React 状态管理方案深度对比
开发语言·前端·react
胡志辉的博客11 小时前
深入浅出理解浏览器事件循环:从一道输出题讲到 Chrome 源码
前端·javascript·chrome·chromium·event loop
代码不加糖11 小时前
js中不会冒泡的事件有哪些?
前端·javascript·vue.js
懂懂tty11 小时前
Vue2与Vue3之间API差异
前端·javascript·vue.js