【问题标题】:Can't understand "state" in reactjs无法理解 reactjs 中的“状态”
【发布时间】:2021-07-24 10:24:26
【问题描述】:

无论我访问哪个站点以明确我对反应状态的疑问,我总是发现这个定义的共同点是: “控制组件行为的一组可观察属性的对象”。而且我仍然不明白反应中的状态。考虑下面的例子

import React,{useState} from 'react';
export const City = ()=>{
    const [altitude,setAltitude] = useState("");
    const getAltitude=()=>{
        navigator.geolocation.watchPosition((position)=>{
            const alt = {
                lat:position.coords.latitude,
                long:position.coords.longitude
            }
            setAltitude(alt);
            console.log(altitude);
        })
    }   
    return(
        <div id="location">
        {getAltitude()} 
        <h3>This is location</h3>
        </div>
    )
}

但是上面的程序也可以不使用state来写,如下图

import React,{useState} from 'react';

export const City = ()=>{
    let lat;
    let long;
    const getAltitude=()=>{
        navigator.geolocation.watchPosition((position)=>{
            lat = position.coords.latitude;
            long = position.coords.longitude;
        })
        console.log(lat,long);
    }
    
    return(
        <div id="location">
        {getAltitude()} 
        <h3>This is location</h3>
        </div>
    )

}

如果我们也可以这样写,那么状态在反应中的用途是什么。 如果我错了,我要求你详细解释我。除非这个疑问没有弄清楚,否则我无法入睡。

【问题讨论】:

  • 如果您使用常规变量,那么如果/当这些变量发生变化时,您的组件将不会重新渲染。例如:如果watchPosition 的回调在一段时间内多次执行,而不使用setAltitude,您的组件将只会渲染初始 JSX 而不会使用更新值渲染它(请注意,经常使用状态值在返回的 JSX 中呈现给用户,因此您希望组件在变量/状态更改时重新呈现)
  • 您的示例在每次渲染时都添加了一个新的监视处理程序,并且从不清除它们。您不希望注册单个监视处理程序并让它在其成功回调中更新状态。您还想在卸载时清除它。查看 useEffect 及其与 useState 的交互。

标签: javascript reactjs


【解决方案1】:

为了便于理解,我创建了这两个 sn-ps,一个使用状态变量,另一个使用常规 js 变量。

  1. 使用状态变量

const { useState } = React;

const Counter = () => {
  const [count, setCount] = useState(0);
  
  const onClick = () => {
    //Update the state
    setCount(c => c + 1);
  }
  
  return (
    <div>
      Count: {count}
      <div>
        <button onClick={onClick}>Increment</button>
      </div>
    </div>
  )
}

ReactDOM.render(<Counter />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

<div id="react"></div>
  1. 使用常规变量

const { useState } = React;

const Counter = () => {
  let count = 0; 
  
  const onClick = () => {
    //Update the variable
    count += 1;
    console.log(count);
  }
  
  return (
    <div>
      Count: {count}
      <div>
        <button onClick={onClick}>Increment</button>
      </div>
    </div>
  )
}

ReactDOM.render(<Counter />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

<div id="react"></div>

在上述两种情况下,我们都在更新按钮点击次数,但在情况 1 中,更新后的值会显示在 DOM 上,而在情况 2 中则不会。

因此,基本上,当您想要在变量更改时重新渲染组件时,我们会将这些变量保持在状态中。 React 将能够理解状态变化并相应地更新 DOM

【讨论】:

  • 除了这个很好的解释之外,我想添加更多细节以使用useState。如果使用常规的 js 声明,每当组件中的某些内容更新(例如使用 onClick 函数单击按钮)时,这些常规 js 声明将一次又一次地工作,因此它可能会导致大型组件中的内存泄漏。
  • 哇。这么好的解释。我明白了。
【解决方案2】:

正如您在引文中正确说明的那样,React 维护了一个状态,除了一些其他功能之外,该状态用于确定何时重新渲染您的组件。在您的示例中,您似乎想为watchPosition 添加一个事件侦听器,并在您的City 组件中显示计算值。如果我是正确的,请考虑这个例子:

import React,{useState} from 'react';

export const City = ()=>{

    const [altitude,setAltitude] = useState({});

    const calculateAltitude=()=>{
        navigator.geolocation.watchPosition((position)=>{
            const alt = {
                lat:position.coords.latitude,
                long:position.coords.longitude
            }
            setAltitude(alt); // you set the state here
        })
    }   

    calculateAltitude(); // This function is called on each render. It's better to put it into a "componentDidMount" equivalent (second example)

    return(
        <div id="location">
        <h3>This is the location</h3>
        <div>Lat: {altitude.lat}</div> {/*You use the state here*/}
        <div>Lat: {altitude.long}</div>
        </div>
    )
}

每次执行 watchPosition 时,您的状态 altitude 都会更新并且组件将重新渲染。这意味着,渲染函数被执行,altitude 的当前状态被用来显示纬度和经度。在第一个示例中,calculateAltitude() 将在每次渲染时执行。由于这不是最佳实践,您应该将该调用放入具有空数组依赖项的 useEffect 挂钩中。它等效于 React 类组件的 componentDidMount() 函数 (React.Component)。 You can find a good explanation here.

所以,为了有一个干净的代码,你应该使用这个组件:

import React,{useState, useEffect} from 'react';
export const City = ()=>{

  const [altitude,setAltitude] = useState({});

  const calculateAltitude=()=>{
    
    navigator.geolocation.watchPosition((position)=>{ // each time this geolocation lib calls your function, your state will be updated.
      const alt = {
        lat:position.coords.latitude,
        long:position.coords.longitude
      }
      setAltitude(alt); // you set the state here
    })
  }
  
  useEffect(() => 
  {
    calculateAltitude() // register your event listener once.
  },[]) // on Component mount. Executed once.
  

  return(
    <div id="location">
      <h3>This is the location</h3>
      <div>Lat: {altitude.lat}</div> {/*You use the state here. It is updated each time your geolocation lib calls your listener.*/}
      <div>Lat: {altitude.long}</div>
    </div>
  )
}

我建议仔细阅读 React 状态。这里有一些很好的链接:

【讨论】:

    【解决方案3】:

    React 的基础特性之一是它允许您在更改变量后更新您的 UI,或者换句话说,您的应用程序的 HTML 输出。在 React 中,状态是一种声明变量的方式,根据您的业务逻辑,这些变量最终可以更新 UI。 React 通过跟踪状态并重新呈现需要更新的 HTML 部分来做到这一点。

    在您的示例中,您将 altitude 设置为您的状态的一部分,但您的逻辑不会在任何地方更新 UI — 它只是在首次加载时确定地理位置。如果这是你想要的,那很好,你不需要状态。但是,如果您想对 HTML 进行更新,例如如果您想在地图上显示用户的实时位置,您可以使用 React 的状态:您将位置更新写入状态,并且需要一些自定义逻辑来处理如果 altitude 值有会发生什么改变了。您可以将此自定义逻辑编写为side effect

    【讨论】:

      【解决方案4】:

      状态变量将可以访问到 jsx (我的意思是在组件的渲染部分),所以在你的例子中,altitude 可以在 html 部分中访问,但如果你没有将它分配给状态变量将不会可以访问它

      return(
              <div id="location">
              <h3>This is location {altitude.alt}</h3>
              </div>
          )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-09-20
        • 2021-10-14
        • 1970-01-01
        • 1970-01-01
        • 2020-04-17
        • 1970-01-01
        • 2016-04-03
        • 2019-01-28
        相关资源
        最近更新 更多