反应挂钩状态不匹配

时间:2020-10-22 16:40:16

标签: reactjs react-hooks use-state

我创建了一个自定义钩子,用于监视滚动行为。但是,当我从使用该挂钩的组件中更改状态时,确实从控制台日志中看到了状态更改,但是一旦开始滚动,该状态的原始值为true。更奇怪的是,react dev工具与控制台日志输出不匹配。

import React, { useEffect } from 'react';
import useExample from './useExample';


function Example() {
  const [status, setStatus] = useExample();
  console.log(`example, status: ${status}`);


  useEffect(() => {
    setStatus(false);
  },[]);

  useEffect(() => {
    setInterval(() => console.log(status), 2000);
  }, [])

  return (<div>
    Something scrollable
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
  </div>);

}

export default Example;
import React, { useState, useEffect } from 'react';

const useExample = () => {
  const [status, setStatus] = useState(true);
  console.log(`useExample status: ${status}`);
  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  function handleScroll() {
    console.log(`handle scroll, status: ${status}`);
  }

  return [status, setStatus];
};

export default useExample;

我更新了功能。即使在Example.js中的第一个useEffect中更改了状态,setInterval函数也始终返回true。 React dev tools console log

更新,如果我将其更改为此,它将起作用,我认为问题与事件侦听器的状态范围有关。需要将其删除并以正确的状态进行更新。

import React, { useState, useEffect, useCa } from 'react';

const useExample = () => {
  const [status, setStatus] = useState(true);
  console.log(`useExample status: ${status}`);
  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [status]);

  useEffect(() => {
    console.log(`${status} useffect`);
  }, [status]);

  function handleScroll() {
    console.log(`handle scroll, status: ${status}`);
  }

  return [status, setStatus];
};

export default useExample;

1 个答案:

答案 0 :(得分:0)

您没有在示例中正确导出函数,但是将其导入父组件,在子组件上使用useState,如果要将函数作为子组件分开,则状态应位于父组件中,将其导入到您的状态最初设置为true的孩子中,您的useExample将始终返回true。

export const useExample = (status) => {

  console.log(`useExample status: ${status}`);

  function handleScroll() {
    console.log(`handle scroll, status: ${status}`);
  }

  useEffect(() => {
     window.addEventListener('scroll', handleScroll);
     return () => window.removeEventListener('scroll', handleScroll);
  }, []);

};

在父级中应该是

import {useExample} from './useExample';

useExample(status);

但是由于函数内部是useEffect,因此您可以像这样在父组件中编写它。这样会更容易。

import React, { useState, useEffect } from 'react';

function Example() {
   const [status, setStatus] = useState(true);


   function handleScroll() {
     console.log(`handle scroll, status: ${status}`);
   }

   useEffect(() => {
     window.addEventListener('scroll', handleScroll);
     return () => window.removeEventListener('scroll', handleScroll);
   }, []);


   useEffect(() => {
     setStatus(false);
   },[]);

   useEffect(() => {
     setInterval(() => console.log(status), 2000);
   }, [])

   return (<div>
     Something scrollable
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
   </div>);

}

export default Example;