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

0 阅读3分钟

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


1. 直接修改State?大忌!

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

// ❌ 错误示范:直接修改state
this.state.count = 10;  

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


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

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

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异步的,如果依赖前一个状态,应该用函数式更新:

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

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

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

import { useState } from 'react';

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

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

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

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

setCount((prevCount) => prevCount + 1);

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

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

const [user, setUser] = useState({ name: 'Alice', age: 25 });

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

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

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

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

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不会立即更新

// ❌ 连续调用setState,count只会+1
setCount(count + 1);
setCount(count + 1);

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

② useEffect依赖问题

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

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

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

总结

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

⭐  写在最后

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

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

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

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

✅ 解答我文章中一些疑问

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

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

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

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