一个危险的编码习惯

const Component = () => {
  useEffect(() => {}, [])
  return <div>Demo</div>
};

// 是否想过,这两种调用方式有什么区别?
Component()   // 这样写会怎样?
<Component /> // 这样写会怎样?

先说答案:第一种写法可能会让你的应用崩溃!

直接调用组件函数(如 Component())是一个危险动作,它会绕开 React 的调度机制,导致上下文状态错乱,可能让你的应用崩溃!!

下面来挖掘一下这个容易被忽视但很危险的问题。

问题重现:状态错乱&异常

通过一个实验直观感受问题所在:

function App() {
  const [count, setCount] = useState(0)
  return (
    <>
      <button onClick={() => setCount(count + 1)}>点击: {count}</button>
      {count % 2 === 0 ? A() : B()}
      {count === 2 && A()}
    </>
  )
}

function A() {
  const [value, setValue] = useState('A')
  return <div>组件A: {value}</div>
}

function B() {
  const [value, setValue] = useState('B')
  return <div>组件B: {value}</div>
}

现象结果

React 如何管理组件状态

函数组件的”状态困境”

普通函数调用没有状态持久性:

function simpleFunction() {
  let count = 0
  count++
  return count
}

simpleFunction() // 返回 1
simpleFunction() // 还是返回 1,每次都是全新作用域

React 的解决方案:Fiber 架构与 Hooks 链表

React 通过 Fiber 架构为每个组件建立独立的状态存储:

React 需要在函数组件外部存储状态。为了管理组件树和状态,React 内部使用了一种叫做 Fiber 的数据结构

// 每个组件都对应一个 Fiber 节点
const fiber = {
  type: Component,        // 组件类型
  memoizedState: null,    // Hooks 链存储在这里
  // ... 其他属性
}