Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react 和 vue 在 state 处理上的差异 #53

Open
chiyan-lin opened this issue Jan 1, 2025 · 1 comment
Open

react 和 vue 在 state 处理上的差异 #53

chiyan-lin opened this issue Jan 1, 2025 · 1 comment

Comments

@chiyan-lin
Copy link
Owner

react

import { useState } from 'react';

export default function Form() {
  const [to, setTo] = useState('Alice');
  const [message, setMessage] = useState('你好');

  function handleSubmit(e) {
    e.preventDefault();
    setTimeout(() => {
      alert(`你向 ${to} 说了${message}`);
    }, 5000);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        To:{' '}
        <select
          value={to}
          onChange={e => setTo(e.target.value)}>
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">发送</button>
    </form>
  );
}

image

一个会在五秒延迟之后发送一条消息的表单, 以下场景:

  1. 你按下“发送”按钮,向 Alice 发送“你好”。
  2. 在五秒延迟结束之前,将“To”字段的值更改为“Bob”
  3. 可以看到 虽然我们修改了 name 但是最后显示的是 前一个

每个渲染(以及其中的函数)始终“看到”的是 React 提供给这个 渲染的 state 快照

这句话我的理解是 当上一次完整的渲染周期 也就是选择了 alice 点击发送之后,react 保存的渲染是

    <form onSubmit={(e) => {
          e.preventDefault();
          setTimeout(() => {
            alert(`你向 Alice 说了${message}`);
          }, 5000);
        }}>
      <label>
        To:{' '}
        <select
          value={to}
          onChange={e => setTo(e.target.value)}>
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">发送</button>
    </form>

被 push 到settimeout 队列的是一个快照值,而不是引用值

@chiyan-lin
Copy link
Owner Author

chiyan-lin commented Jan 1, 2025

然后来看下用 vue 的时候,同样的场景 vue 是怎么表现的

<script setup>
import { ref } from 'vue'

const name = ref('Alice')
const msg = ref('Hello World!')

const handleSubmit = function(e) {
    e.preventDefault();
    setTimeout(function () {
      alert(`你向 ${name.value} 说了${msg.value}`);
    }, 5000);
}
const handleChange = function() {

}
</script>

<template>
<form @submit="handleSubmit">
      <label>
        To: {{name}}
        <select
          v-model="name"
          @change="handleChange">
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        v-model="msg"
      />
      <button type="submit">发送</button>
    </form>
</template>

image

可以看到 vue 不想 react 这样,有个快照的概念,点击了之后显示的是 blob ,引用的是最新的值。

这就是 react 和 vue 在数据处理上的一个巨大的不同,那么如果想让 react 也实现像 vue 这样的数据方式要怎么做呢

import { useState } from 'react';

export default function Form() {
  // 全局数据
  if (!window.obj) {
    window.obj = { name: 'Alice' }
  }
  const [to, setTo] = useState({ value: window.obj });
  const [message, setMessage] = useState('你好');

  function handleSubmit(e) {
    e.preventDefault();
    setTimeout(() => {
      alert(`你向 ${to.value.name} 说了${message}`);
    }, 5000);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        To: {to.value.name} {' '}
        <select
          value={to.value.name}
          onChange={e => {
            // 修改全局数据,然后 set 回去,触发 react 的 render 更新
            window.obj.name = e.target.value
            setTo({ value: window.obj  })
          }}>
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">发送</button>
    </form>
  );
}

像这样,把 to 挂载到一个全局的变量上,脱离快照就可以了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant