React Hooks - 使用 useState 与仅使用变量

IT技术 javascript node.js reactjs react-hooks
2021-03-31 18:07:04

React Hooks 为我们提供了 useState 选项,我总是看到 Hooks 与 Class-State 的比较。但是 Hooks 和一些常规变量呢?

例如,

function Foo() {
    let a = 0;
    a = 1;
    return <div>{a}</div>;
}

我没有使用 Hooks,它会给我相同的结果:

function Foo() {
    const [a, setA] = useState(0);
    if (a != 1) setA(1); // to avoid infinite-loop
    return <div>{a}</div>;
}

那么有什么不同呢?在这种情况下使用 Hooks 会更加复杂……那么为什么要开始使用它呢?

5个回答

原因是如果你重新useState渲染视图。变量本身只会改变内存中的位,你的应用程序的状态可能会与视图不同步。

比较这个例子:

function Foo() {
    const [a, setA] = useState(0);
    return <div onClick={() => setA(a + 1)}>{a}</div>;
}

function Foo() {
    let a = 0;
    return <div onClick={() => a + 1}>{a}</div>;
}

在这两种情况下a,单击都会更改,但仅当您useState正确使用视图时才会显示a的当前值。

useRef如果他不想重新渲染视图,他仍然可以使用问题仍然是他应该使用局部变量还是 React 引用。例如,如果您有需要清除的超时,或者使用 axios 的正在进行的 http 请求,您是否将超时或 axios 源存储在变量或 React ref 中?
2021-06-01 18:07:04
@MosheNagar 如果您从 props 派生数据,建议使用局部变量而不是将数据保持在状态,因为组件无论如何都会在 prop 更改时重新渲染,因此视图将与数据同步。将它们置于状态只会导致不必要的重新渲染 - 首先是道具更改,然后是状态更改。
2021-06-04 18:07:04
看待这个答案的另一种方式是认为在第二种情况下,变量a将在完成执行后被垃圾收集,而在第一种情况下,因为它利用useState它将保留a
2021-06-11 18:07:04
谢谢!因此,如果我不需要渲染视图 - 只是一种将我的数据(道具)组织到某个数组中的方法 - 我可以使用 'let' 吗?它对我有用,我只是想知道它可以并且可以接受。
2021-06-15 18:07:04
@Tom 一般规则是对派生状态使用局部变量。对于任何其他用途useRef(如果您不想重新渲染)或useState(如果您想要重新渲染)。在定时器的情况下,由于它们是副作用,它们应该在useEffect钩子中启动如果您只想timerId进行清理,可以将其保存在handler的局部变量中。如果您希望能够从组件中的其他位置清除计时器,您应该使用useRef. 存储timerId组件的局部变量中将是一个错误,因为局部变量在每次渲染时都会“重置”。
2021-06-21 18:07:04

局部变量将在每次渲染时重置,而状态将更新:

function App() {
  let a = 0; // reset to 0 on render/re-render
  const [b, setB] = useState(0);

  return (
    <div className="App">
      <div>
        {a}
        <button onClick={() => a++}>local variable a++</button>
      </div>
      <div>
        {b}
        <button onClick={() => setB(prevB => prevB + 1)}>
          state variable b++
        </button>
      </div>
    </div>
  );
}

编辑 serene-galileo-ml3f0

Local variables will get reset every render upon mutation whereas state will update. 功能组件是正确的。类组件呢?
2021-06-13 18:07:04
@NguyễnVănPhong 如果您指的是类属性,不,它们存在于组件生命周期之外。如果您指的是render生命周期方法中声明的任何变量例如),这些变量将在每次渲染时重新声明,就像在功能组件中一样。
2021-06-13 18:07:04
这就说得通了。+1
2021-06-16 18:07:04

更新状态将使组件再次重​​新渲染,但本地值不会。

在您的情况下,您在组件中呈现了该值。这意味着,当值改变时,组件应该重新渲染以显示更新的值。

所以使用会useState比正常的本地值更好

function Foo() {
    let a = 0;
    a = 1; // there will be no re-render.
    return <div>{a}</div>;
}

function Foo() {
    const [a, setA] = useState(0);
    if (a != 1) setA(1); // re-render required
    return <div>{a}</div>;
}
function Foo() {
    const [a, setA] = useState(0);
    if (a != 1) setA(1); // to avoid infinite-loop
    return <div>{a}</div>;
}

相当于

class Foo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            a: 0
        };
    }
    // ...
}

什么useState回报是两件事情:

  1. 新状态变量
  2. 该变量的设置器

如果你打电话,setA(1)你会打电话this.setState({ a: 1 })并触发重新渲染。

您的第一个示例之所以有效,是因为数据基本上永远不会改变。使用的要点setState是在状态挂起时重新渲染整个组件。因此,如果您的示例需要某种状态更改或管理,您将很快意识到更改值是必要的,并且要使用变量值更新视图,您将需要状态和重新渲染。