发布于 2026-01-06 0 阅读
0

像专业人士一样使用 useState() ✨ 由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

像专业人士一样使用 useState() ✨

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

这篇博文涵盖了关于状态和 React Hook 的所有概念,useState从基础到高级模式。本文假设你已经了解 React 的基础知识,例如组件、属性和 JSX。

counterhello world国家管理。

什么是状态?为什么 React 需要状态管理?⚛️

function Counter() {
  // State: a counter value
  const [counter, setCounter] = useState(0)

  // Action: code that causes an update to the state when something happens
  const increment = () => {
    setCounter(counter + 1)
  }

  // View: the UI definition
  return (
    <div>
      Value: {counter} <button onClick={increment}>Increment</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

正如您在本例中看到的,组件主要由三个部分Counter组成。

  • 国家是驱动我们应用程序的真理。
  • 视图是基于状态的用户界面
  • 操作是指应用程序中发生的、会改变状态的事件。

React 使用状态值(由 useState、useReducer 等 hook API 生成)来判断何时更新应用程序的 UI(视图)部分。每当状态值发生变化时,React 都会更新组件,使 UI 的状态与组件的状态保持一致。

useState Hook 🎣

useState这是一个接受一个参数作为状态初始值的函数(初始值可以是任意类型),并返回一个包含两个元素的数组:第一个元素是状态值,第二个元素是用于更新状态值的更新函数。返回的数组通常是解构的,因此我们可以随意命名变量,但最佳实践和常见约定是在set更新函数名前加上前缀。

// you can pass any data-type
setState() // if you don't pass anything than value will be updated with undefined 
setState('Thanks') // String
setState(4) // Number
setState(['reading']) // array 
setState({ share : 💗 }) // object
setState(null) // null 
Enter fullscreen mode Exit fullscreen mode

在我们的 Counter 组件中0,是状态的初始值,我们使用解构来命名我们的两个变量counter每次单击按钮时,都会将计数器值更新为 1 setCountersetCounter

function Counter() {
  const [counter, setCounter] = useState(0)

  const increment = () => {
    setCounter(counter + 1)
  }

  return (
    <div>
      Value: {counter} <button onClick={increment}>Increment</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

状态的惰性初始化🦥

每次 React 重新渲染组件时,useState(initialState)都会执行该函数。如果初始状态是一些耗时的函数计算,例如从 localStorage 读取数据、处理大量数据、实例具有多个方法(例如 `get`DraftJs或 ` ThreeJsget` 实例),那么组件可能会遇到一些性能问题。

// format : useState(() => initalState) 

const [token, setToken] = useState(() => window.localStorage.getItem('token') || '')

Enter fullscreen mode Exit fullscreen mode

我们可以使用延迟初始化来避免性能瓶颈,你只需要将初始状态放入函数中即可。

使用回调更新状态🤙

 const [counter, setCounter] = useState(0);

 const increment = () => {
    setCounter(counter + 1);
    setTimeout(() => {
      setCounter(counter + 1);
    }, 1000);
  };
Enter fullscreen mode Exit fullscreen mode

我们已经修改了前面示例中的递增函数,现在我们在函数中添加了异步行为,你认为输出结果会是什么?









请稍作停顿思考,








前方剧透!







你会看到,点击按钮一次后,即使我们有 2 次setCounter通话,我们仍然会得到一个更新后的新计数,其中只有 1

所以到底发生了什么?🤔

问题在于第二次调用得到的setCounter计数器值与第一次调用得到的计数器值相同。在这个例子中,两次调用都setCounter得到了相同的计数器值,0因此它们都将其更新为1

但是为什么更新程序第二次获取到的值为0呢?😕

为此,你需要了解 React 中重新渲染的实际工作原理。我们不会深入探讨,但简而言之,重新渲染意味着如果你的状态发生变化,整个组件都会被新的组件替换。在这个例子中,`whole`Counter会被再次调用,然后获取新的值。这里我们使用了多次连续更新,并且由于闭包的 setCounter存在,我们可以访问counter从数组解构中得到的变量 `one`,其值为 0。

0在这个例子中,当按钮被点击时,初始值从 0 更新为 1,但为了获得更新后的状态 (1),React 需要重新渲染组件,但在这里我们再次调用它来将计数器更新为 +1,并且在一秒钟后更新值时,setCounter计数器会像这样得到01

对于大多数async活动来说useEffect,这将是更好的选择。对于更复杂的状态也是如此useReducer

解决方案 🔥

当新状态依赖于先前的状态时,您可以使用回调函数更新状态。

const increment = () => {
    setCounter(counter + 1);
    setTimeout(() => {
      // callback inside a updater function
      setCounter(counter => counter + 1);
    }, 1000);
  };
Enter fullscreen mode Exit fullscreen mode

如果你用这个新的函数替换原来的增量函数,你将得到的是对内部状态的引用,而不是状态的闭包值。

使用案例💼

// toggle a boolean
const [toggled, setToggled] = useState(false);
setToggled(toggled => !toggled);

// Update an object 
const [size, setSize] = useState({ height : 500, width : 800})
setSize(currentSize => ({...currentSize , height : 700}))

// Update items in array
const [items, setItems] = useState([]);
setItems(items => [...items, 'push']);
Enter fullscreen mode Exit fullscreen mode
文章来源:https://dev.to/shubham_sns/usestate-like-a-pro-1pbc