react를 사용하여 x초마다 API 폴링
1, 2초마다 화면에서 데이터 업데이트 정보를 모니터링해야 합니다.이 구현을 사용하는 방법은 다음과 같습니다.
componentDidMount() {
this.timer = setInterval(()=> this.getItems(), 1000);
}
componentWillUnmount() {
this.timer = null;
}
getItems() {
fetch(this.getEndpoint('api url endpoint'))
.then(result => result.json())
.then(result => this.setState({ items: result }));
}
이것이 올바른 접근법입니까?
API만 있고 소켓을 사용하도록 변경할 수 있는 권한이 없기 때문에 폴링하는 방법밖에 없습니다.
여론조사에 따르면 당신은 적절한 접근을 하고 있습니다.하지만 위의 코드에는 한 가지 함정이 있습니다.
componentDidMount() {
this.timer = setInterval(()=> this.getItems(), 1000);
}
componentWillUnmount() {
this.timer = null; // here...
}
getItems() {
fetch(this.getEndpoint('api url endpoint'))
.then(result => result.json())
.then(result => this.setState({ items: result }));
}
여기서의 문제는 컴포넌트가 마운트 해제되면 저장된 인터벌에 대한 참조가 됩니다.this.timer
로 설정되어 있다.null
, 아직 정지되지 않았습니다.컴포넌트가 마운트 해제된 후에도 인터벌은 핸들러를 계속 호출하여setState
더 이상 존재하지 않는 컴포넌트에 있습니다.
적절하게 대처하기 위해clearInterval(this.timer)
그 후 세팅this.timer = null
.
또,fetch
콜이 비동기이기 때문에 같은 문제가 발생할 수 있습니다.취소할 수 있도록 하고 있으면 취소합니다.fetch
불완전합니다.
이게 도움이 됐으면 좋겠어요.
React Polling을 검색했을 때는 오래된 질문이었지만 Hooks에 맞는 답변이 없었습니다.
// utils.js import React, { useState, useEffect, useRef } from 'react'; export const useInterval = (callback, delay) => { const savedCallback = useRef(); useEffect(() => { savedCallback.current = callback; }, [callback]); useEffect(() => { function tick() { savedCallback.current(); } if (delay !== null) { const id = setInterval(tick, delay); return () => clearInterval(id); } }, [delay]); }
출처 : https://overreacted.io/making-setinterval-declarative-with-react-hooks/
그런 다음 Import하여 사용할 수 있습니다.
// MyPage.js
import useInterval from '../utils';
const MyPage = () => {
useInterval(() => {
// put your interval code here.
}, 1000 * 10);
return <div>my page content</div>;
}
다음과 같은 조합을 사용할 수 있습니다.setTimeout
그리고.clearTimeout
.
setInterval
는 이전 콜의 성공 여부에 관계없이 'x'초마다 API 콜을 기동합니다.이로 인해 브라우저 메모리가 잠식되어 시간이 지남에 따라 성능이 저하될 수 있습니다.게다가 서버가 다운되었을 경우,setInterval
는, 다운 상태를 모르는 채로 서버를 계속 폭격합니다.
반면에.
다음을 사용하여 재귀할 수 있습니다.setTimeout
이전 API 호출이 성공한 경우에만 후속 API 호출을 실행합니다.이전의 콜이 실패했을 경우는, 타임 아웃을 클리어 해, 그 이후의 콜을 기동하지 말아 주세요.필요에 따라서, 실패했을 경우에 유저에게 경고합니다.이 프로세스를 재시작하려면 페이지를 새로 고치십시오.
다음은 코드 예시입니다.
let apiTimeout = setTimeout(fetchAPIData, 1000);
function fetchAPIData(){
fetch('API_END_POINT')
.then(res => {
if(res.statusCode == 200){
// Process the response and update the view.
// Recreate a setTimeout API call which will be fired after 1 second.
apiTimeout = setTimeout(fetchAPIData, 1000);
}else{
clearTimeout(apiTimeout);
// Failure case. If required, alert the user.
}
})
.fail(function(){
clearTimeout(apiTimeout);
// Failure case. If required, alert the user.
});
}
@AmitJS94, 이 기사에서 GavKilbride가 언급한 메서드에 추가되는 인터벌을 중지하는 방법에 대한 자세한 섹션이 있습니다.
작성자는 지연 변수의 상태를 추가하고 간격을 일시 정지할 때 해당 지연에 대해 "null"을 전달하도록 지시했습니다.
const [delay, setDelay] = useState(1000);
const [isRunning, setIsRunning] = useState(true);
useInterval(() => {
setCount(count + 1);
}, isRunning ? delay : null);
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
기사를 꼭 읽어보고 자세한 내용을 더 잘 이해하세요.완벽하고 잘 쓰여져 있어요!
Vasanth가 언급했듯이, 나는 다음을 선호한다.
- set Timeout을 사용하여 마지막 요청 종료 후 다음 요청 시작까지의 시간을 측정합니다.
- 지연 후가 아니라 즉시 첫 번째 요청을 한다
- @KyleMit https://stackoverflow.com/a/64654157/343900의 답변에서 영감을 얻어
import { useEffect, useRef } from 'react';
export const useInterval = (
callback: Function,
fnCondition: Function,
delay: number,
) => {
const savedCallback = useRef<Function>();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
let id: NodeJS.Timeout;
const tick = async () => {
try {
const response =
typeof savedCallback.current === 'function' &&
(await savedCallback.current());
if (fnCondition(response)) {
id = setTimeout(tick, delay);
} else {
clearTimeout(id);
}
} catch (e) {
console.error(e);
}
};
tick();
return () => id && clearTimeout(id);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [delay]);
};
WORKS: fnCondition inside를 사용합니다.이것은 마지막 요구로부터의 응답에 근거한 조건일 수 있습니다.
//axios-hooks
const {
data,
isLoadingData,
getData,
} = api.useGetData();
const fnCondition = (result: any) => {
const randomContidion = Math.random();
//return true to continue
return randomContidion < 0.9;
};
useInterval(() => getData(), fnCondition, 1000);
작동하지 않음: 지연을 null로 전달하여 useInterval을 중지하는 것은 다음 코드에서는 작동하지 않습니다.https://www.aaron-powell.com/posts/2019-09-23-recursive-settimeout-with-react-hooks/
(동작하는 것 같은 느낌이 들 수도 있지만, 몇 번을 시작/정지하면 고장납니다.
const [isRunning, setIsRunning] = useState(true);
const handleOnclick = () => {
setIsRunning(!isRunning);
};
useInterval(() => getData(), isRunning ? 1000 : null);
<button onClick={handleOnclick}>{isRunning ? 'Stop' : 'Start'}</button>
요약: fnCondition을 전달하여 useInterval을 중지할 수 있지만, 지연을 전달하여 useInterval을 중지할 수 없습니다.
다음은 심플하고 완전한 솔루션입니다.
X초마다 폴링
로직이 실행될 때마다 타임아웃을 늘려 서버에 과부하가 걸리지 않도록 하는 옵션이 있습니다.
최종 사용자가 컴포넌트를 종료할 때 타임아웃을 클리어합니다.
//mount data componentDidMount() { //run this function to get your data for the first time this.getYourData(); //use the setTimeout to poll continuously, but each time increase the timer this.timer = setTimeout(this.timeoutIncreaser, this.timeoutCounter); } //unmounting process componentWillUnmount() { this.timer = null; //clear variable this.timeoutIncreaser = null; //clear function that resets timer } //increase by timeout by certain amount each time this is ran, and call fetchData() to reload screen timeoutIncreaser = () => { this.timeoutCounter += 1000 * 2; //increase timeout by 2 seconds every time this.getYourData(); //this can be any function that you want ran every x seconds setTimeout(this.timeoutIncreaser, this.timeoutCounter); }
함수 컴포넌트에서 후크를 사용하는 간단한 예를 다음에 나타냅니다.이 예에서는 설정된 간격으로 데이터가 갱신됩니다.
import React from 'react';
import { useEffect, useState } from 'react';
export default function App() {
let [jokes, setJokes] = useState('Initial');
async function fetchJokes() {
let a = await fetch('https://api.chucknorris.io/jokes/random');
let b = await a.json();
setJokes(b.value);
}
// Below function works like compomentWillUnmount and hence it clears the timeout
useEffect(() => {
let id = setTimeout(fetchJokes, 2000);
return () => clearTimeout(id);
});
return <div>{jokes}</div>;
}
또는 API 호출에 액시스를 사용할 수도 있습니다.
function App() {
const [state, setState] = useState("Loading.....");
function fetchData() {
axios.get(`https://api.chucknorris.io/jokes/random`).then((response) => {
setState(response.data.value);
});
}
useEffect(() => {
console.log("Hi there!");
let timerId = setTimeout(fetchData, 2000);
return ()=> clearInterval(timerId);
});
return (
<>
This component
<h3>{state}</h3>
</>
);
}
언급URL : https://stackoverflow.com/questions/46140764/polling-api-every-x-seconds-with-react
'programing' 카테고리의 다른 글
Redux Reducer에서 스토어의 초기 상태 확인 (0) | 2023.03.13 |
---|---|
커스텀 필드로 투고를 주문하다 (0) | 2023.03.13 |
인증된 CORS 요청의 비행 전 OPTIONS 요청은 왜 Chrome에서는 작동하지만 Firefox에서는 작동하지 않습니까? (0) | 2023.03.13 |
스프링 nullable 주석이 알 수 없는 열거 상수 경고를 생성합니다. (0) | 2023.03.13 |
카트 버튼의 woocommerce 코드 (0) | 2023.03.13 |