反应钩子第一次没有设置状态

Posted

技术标签:

【中文标题】反应钩子第一次没有设置状态【英文标题】:React hooks not set state at first time 【发布时间】:2019-12-15 12:54:01 【问题描述】:

我的钩子有问题。

我正在使用 react-hooks,我有一个按钮,它可以在 onClick 从 api 获取数据并使用它设置状态。

问题是:

当我第一次单击按钮时,我从 api 获得响应,但无法将其设置为状态。当第二次单击按钮时,我可以设置状态。为什么会这样?

这是我的组件的样子:

function App() 
  const [a, setA] = useState(null);


  const fetchData = () => 
    let data = 
        id: 1
    


    axios.post(baseUrl, data)
    .then(res => 
      if (res.data) 
        setA(res.data)
      
      console.log(a)
    )

  

  return (
    <div className="App">
      <div>
        <button onClick=fetchData></button>
      </div>
    </div>
  );


export default App;

我尝试使用这样的 fetchData 函数:

 function fetchData() 
        let data = 
            id: 1
        


        axios.post(baseUrl, data)
        .then(res => 
          if (res.data) 
            setA(res.data)
          
          console.log(a)
        )

      

但也无济于事

【问题讨论】:

@user3348410,您应该使用 useEfect 挂钩进行获取,因为您使用的是异步调用。 会怎样@Asking setA() 在该范围内不会更改 a,但提取确实第一次工作。 @AtulKumar 是 Fetch API,而不是 axios。 Axios 没有 json() 异步方法。 你能给我一些例子吗? useEffect 是不是就像 componentDidMount 一样?我不想在 componentDidmount 中获取某些东西我不想在用户点击按钮时获取数据 【参考方案1】:

a 是一个常量。无法更改它,因此您在 fetchData 末尾的 console.log 语句永远不会注销与创建 fetchData 时 a 所具有的值不同的值。

所以setA 不是这样做的。 setA 的重点不是改变 const 的值,而是让组件重新渲染。在该新渲染中,将创建一组新变量,并且新的 a 将获得新值。将您的 console.log 移出组件的主体,您将看到它以新值重新呈现。

简而言之:您的代码似乎已经在运行,只是您的日志记录有误。

【讨论】:

【参考方案2】:

如果您的范围是获取数据,请使用:

const [data, setData] = useState("");
  useEffect(async () => 
    const result = await axios(
      'here will be your api',
    );
    setData(result.data);
  );

现在您的回复将存储在data 变量中。

【讨论】:

useEffect 我认为对 componentDidMount 有效,不是吗?我不希望它会在 onClick 上工作【参考方案3】:

我不会为它使用效果,如果道具或状态发生变化,效果会很有用,因此可以替代生命周期方法,如 componentDidMount、componentDidUpdate、componentWillUnmount 等。但在你的情况下,这些道具还没有改变(你想改变你的状态)。顺便说一句,请注意@Asking 的方法将在每次重新渲染(道具或状态更改)时获取数据。如果要使用 useEffect,请务必添加第二个参数来告诉 React 何时更新。

通常情况下,您的代码应该可以工作,我还没有测试过,但看起来是合法的。您是否使用开发人员工具来做出反应以检查状态/挂钩是否已更改?因为如果你说它因为console.log 打印而不起作用:请记住setA() 是一个异步函数。当您尝试打印状态时,该状态很可能尚未更改。如果您还没有响应开发人员工具(我强烈推荐),您可以通过在函数中添加以下代码来检查真实状态:

useEffect(() => console.log(a), [a]);

不过,我对您的代码有一些真正的改进:

    function App() 
  const [a, setA] = useState(null);


  const fetchData = useCallback(async () => 
    let data = 
        id: 1
    


    const res = await axios.post(baseUrl, data);
    setA(res.data);

  , []);

  return (
    <div className="App">
      <div>
        <button onClick=fetchData></button>
      </div>
    </div>
  );


export default App;

通过添加useCallback,您可以确保函数被记住并且不会在每次重新渲染时一次又一次地声明。

【讨论】:

对不起,它没有改变任何东西:/ UPS。抱歉,成功了!!!非常感谢,我需要为每个 api 请求使用 useCallBack 对吗? 您实际上不需要 useCallback,它只是一种性能改进和最佳实践。使用 useCallback 时,需要声明依赖参数,所以如果它们发生变化,函数会被重新声明。见docs【参考方案4】:

@Nicholas Tower 已经回答了您的问题。但是如果你正在寻找代码

function App() 
  const [a, setA] = useState(null);


  const fetchData = () => 
    let data = 
        id: 1
    


    axios.post(baseUrl, data)
    .then(res => 
      if (res.data) 
        setA(res.data)
      

    )

  


  console.log(a)
  return (
    <div className="App">
      <div>
        <button onClick=fetchData></button>
      </div>
    </div>
  );


export default App;

只需将日志放在return ( 之前。应该这样做

【讨论】:

实际上我理解了一些我的条目代码很好用的东西,但是当我做出条件作为回报时,比如 a.length ? (

a

):空。它不工作。
在得到a的长度之前。您应该检查 a 是否为空,例如 a && (

a

) 。如果你使用你的代码 a.length ? (

a

) : null 你会得到错误,因为是第一次是 null 并且你试图获取 null 的长度,这会抛出错误
我看到了,我设置的第一个状态为 const [a, setA] = useState([]);但这种情况也没有奏效。这里例如。我的长度是 0 对不起我的错误我把它写成 const [a, setA] = useState(null);我的条件是 a != null (

a

) 。然后效果很好
太棒了。 [a, setA] = useState([]) 不起作用的原因是 a.length 解析为 0 并且 0 在条件内实际上是错误的

以上是关于反应钩子第一次没有设置状态的主要内容,如果未能解决你的问题,请参考以下文章

反应 useState 钩子不使用 axios 调用更新

如何使用反应钩子设置状态数组

在 useState 钩子中反应设置状态

React - useState 钩子第一次和后续设置状态时的奇怪行为

确保在调用函数之前设置状态反应钩子

从另一个组件反应钩子设置状态