Javascript useEffect在初始负载上运行&;更新时-如何限制仅更改?

Javascript useEffect在初始负载上运行&;更新时-如何限制仅更改?,javascript,reactjs,typescript,react-hooks,Javascript,Reactjs,Typescript,React Hooks,在我的代码示例中,我的useEffect订阅了postId,这在任何时候都不会改变。但useEffect仍在运行 有没有办法阻止它运行,并且只有在我更改它时才能启动 import React, {useState, useEffect} from 'react'; import Vim from './Vim'; import './Main.css'; function Main():JSX.Element { const [postId,updatePostId] = useSt

在我的代码示例中,我的useEffect订阅了postId,这在任何时候都不会改变。但useEffect仍在运行

有没有办法阻止它运行,并且只有在我更改它时才能启动

import React, {useState, useEffect} from 'react';
import Vim from './Vim';
import './Main.css';


function Main():JSX.Element { 

  const [postId,updatePostId] = useState<number|null>(null)
  const [content, updateContent] = useState<string>('default text');
  const apiUrl = 'http://127.0.0.1:8000/'

  useEffect(()=>{
    // Detect change in PostID & go download it.
    // Ignore if we are coming from null->number
    console.log('Why am I running?')
    fetch(apiUrl+'get_post/'+postId)
    .then(res=>res.json())
    .then(result=>console.log(result))
  },[postId])


  function loadPost(pid:number):string|null{
    // fetch from API, load post content
    console.log('I can access:'+postId)
    return null;
  }
  
  function backLinks():JSX.Element{
    
    return(
      <div className="backlinks">
      </div>
    )
  }

  return (
    <div className='main'>
      <Vim content={content} />
    </div>
  )
}

export default Main
import React,{useState,useffect}来自“React”;
从“/Vim”导入Vim;
导入“/Main.css”;
函数Main():JSX.Element{
常量[postId,updatePostId]=useState(null)
const[content,updateContent]=useState('defaulttext');
康斯特阿皮乌尔酒店http://127.0.0.1:8000/'
useffect(()=>{
//检测PostID中的更改并下载它。
//如果我们来自null->number,则忽略
console.log('我为什么在运行?')
获取(apirl+'get_post/'+posted)
.then(res=>res.json())
.then(result=>console.log(result))
},[posted])
函数loadPost(pid:number):字符串| null{
//从API获取,加载post内容
console.log('我可以访问:'+posted)
返回null;
}
函数反向链接():JSX.Element{
返回(
)
}
返回(
)
}
导出默认主

事实上,在第一次运行时,
postId
是空的,因为您以这种方式初始化它。所以你也需要注意这一点

useffect
要么接受依赖项数组,要么将其保留为空。在后一种情况下,它只运行一次,因为没有依赖关系,但是在第一种情况下,它既侦听依赖关系的变化,也在组件第一次装载时运行

useEffect(()=>{
  if (postId == null) return;
  ...
}, [postId]);
const isMounted = useRef(null);

useEffect(()=>{
  if (!isMounted.current) return;

  // do your fetch stuff here
  fetch(apiUrl+'get_post/'+postId)
    .then(res=>res.json())
    .then(result=>console.log(result))

}, [isMounted]);

<div ref={isMounted}></div>
对于更一般的方法,您可以使用如下内容

const [ready, setReady] = useState(false);

useEffect(() => {

  setReady(true);

}, [])

useEffect(()=>{
  if (!ready) return;
  ...
}, [postId, ready]);
上述解决方案在大多数情况下都是合理的,但我建议您通过创建一个ref来处理它,将其分配给DOM元素,并等待该ref变为可用。因此,您可以确定组件是第一次渲染的

useEffect(()=>{
  if (postId == null) return;
  ...
}, [postId]);
const isMounted = useRef(null);

useEffect(()=>{
  if (!isMounted.current) return;

  // do your fetch stuff here
  fetch(apiUrl+'get_post/'+postId)
    .then(res=>res.json())
    .then(result=>console.log(result))

}, [isMounted]);

<div ref={isMounted}></div>
const isMounted=useRef(null);
useffect(()=>{
如果(!isMounted.current)返回;
//你在这儿取东西吗
获取(apirl+'get_post/'+posted)
.then(res=>res.json())
.then(result=>console.log(result))
},[isMounted]);

通过这种方式,您不需要额外的重新渲染,因为更新引用不会导致重新渲染。

我有其他示例,其中初始状态可能与更新状态相同,也可能与更新状态不同,但我仍然希望它仅在更改时运行。还有比这更普遍的解决方案吗?
postId
的第一个“变化”是从未定义(我不是说值
未定义
)到初始值(是的,
null
是一个值)。这相当于
componentDidMount()
。第二个更改是从
null
更改为某个数字。如果要忽略这些更改,请忽略这些更改(并告诉您的效果尽早返回),但这就是
useffect()
的工作方式。