React 挂钩管理 API 调用计时器
React hooks to manage API call with a timer
我需要获取 API 调用 returns 一个 URL,对返回的 URL 做一些事情,然后刷新 URL 60 秒。这是我可以在没有钩子的情况下轻松实现的事情,但我想要一个钩子解决方案。
重要:我不打算将其重构为多个组件,或为计时器或 API 调用创建自定义挂钩。
编辑:问题是——这是在挂钩环境中处理计时器的正确方法吗?有没有更好的方法?
import React, { useState, useEffect } from 'react'
import { post } from 'utils/requests'
const FetchUrl = ({ id }) => {
const [url, setUrl] = useState('')
let [count, setCount] = useState(0)
const tick = () => {
let newCount = count < 60 ? count + 1 : 0
setCount(newCount)
}
useEffect(() => {
const timer = setInterval(() => tick(), 1000)
if (count === 0) {
post('/api/return-url/', { id: [id] })
.then(res => {
if (res && res.content) {
setUrl(res.content.url)
}
})
}
return () => clearInterval(timer)
})
return url ? (
<span className="btn sm">
<a href={url} target="_blank" rel="noopener noreferrer">go</a>
</span>
) : null
}
export default FetchUrl
看看是否适合你。
我会把它分成 2 useEffect()
。第一次渲染后 运行(类似于 componentDidMount
)设置计时器。和其他根据计数值进行 API 调用。
注意: 我使用 ref
只是为了区分一个 API 呼叫与另一个呼叫并为其添加一个号码。
请参阅下面的代码段:
const FetchUrl = ({ id }) => {
const [url, setUrl] = React.useState('');
const [count, setCount] = React.useState(0);
const someRef = React.useRef(0);
const tick = () => {
//let newCount = count < 60 ? count + 1 : 0
setCount((prevState) => prevState < 60 ? prevState +1 : 0);
}
function mockAPI() {
return new Promise((resolve,request) => {
someRef.current = someRef.current + 1;
setTimeout(()=>resolve('newData from API call ' + someRef.current),1000);
});
}
React.useEffect(() => {
const timer = setInterval(() => tick(), 100);
return () => clearInterval(timer);
});
React.useEffect(() => {
if (count === 0) {
/*post('/api/return-url/', { id: [id] })
.then(res => {
if (res && res.content) {
setUrl(res.content.url)
}
})
*/
mockAPI().then((data) => setUrl(data));
}
},[count]);
return url ? (
<span className="btn sm">
<div>{count}</div>
<a href={url} target="_blank" rel="noopener noreferrer">{url}</a>
</span>
) : null
}
ReactDOM.render(<FetchUrl/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
我需要获取 API 调用 returns 一个 URL,对返回的 URL 做一些事情,然后刷新 URL 60 秒。这是我可以在没有钩子的情况下轻松实现的事情,但我想要一个钩子解决方案。
重要:我不打算将其重构为多个组件,或为计时器或 API 调用创建自定义挂钩。
编辑:问题是——这是在挂钩环境中处理计时器的正确方法吗?有没有更好的方法?
import React, { useState, useEffect } from 'react'
import { post } from 'utils/requests'
const FetchUrl = ({ id }) => {
const [url, setUrl] = useState('')
let [count, setCount] = useState(0)
const tick = () => {
let newCount = count < 60 ? count + 1 : 0
setCount(newCount)
}
useEffect(() => {
const timer = setInterval(() => tick(), 1000)
if (count === 0) {
post('/api/return-url/', { id: [id] })
.then(res => {
if (res && res.content) {
setUrl(res.content.url)
}
})
}
return () => clearInterval(timer)
})
return url ? (
<span className="btn sm">
<a href={url} target="_blank" rel="noopener noreferrer">go</a>
</span>
) : null
}
export default FetchUrl
看看是否适合你。
我会把它分成 2 useEffect()
。第一次渲染后 运行(类似于 componentDidMount
)设置计时器。和其他根据计数值进行 API 调用。
注意: 我使用 ref
只是为了区分一个 API 呼叫与另一个呼叫并为其添加一个号码。
请参阅下面的代码段:
const FetchUrl = ({ id }) => {
const [url, setUrl] = React.useState('');
const [count, setCount] = React.useState(0);
const someRef = React.useRef(0);
const tick = () => {
//let newCount = count < 60 ? count + 1 : 0
setCount((prevState) => prevState < 60 ? prevState +1 : 0);
}
function mockAPI() {
return new Promise((resolve,request) => {
someRef.current = someRef.current + 1;
setTimeout(()=>resolve('newData from API call ' + someRef.current),1000);
});
}
React.useEffect(() => {
const timer = setInterval(() => tick(), 100);
return () => clearInterval(timer);
});
React.useEffect(() => {
if (count === 0) {
/*post('/api/return-url/', { id: [id] })
.then(res => {
if (res && res.content) {
setUrl(res.content.url)
}
})
*/
mockAPI().then((data) => setUrl(data));
}
},[count]);
return url ? (
<span className="btn sm">
<div>{count}</div>
<a href={url} target="_blank" rel="noopener noreferrer">{url}</a>
</span>
) : null
}
ReactDOM.render(<FetchUrl/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>