我有一个加载器组件,它从一个类组件重构为一个功能组件。代码似乎完全相同,但出于某种原因,在类组件版本中,我在功能版本中没有收到任何警告。 这个错误通常需要在测试中做一些工作,但在这种情况下,我认为组件是有错误的那个。即使我更改了测试(我认为这很容易完成),我对使用此 Loader 的其他组件还有很多其他测试,这意味着我应该更改其中的每一个。
警告信息 Warning: An update to Loader inside a test was not wrapped in act(...).
我会留下两个版本
旧版本 - 类组件(无警告)
import React from 'react'
class Loader extends React.Component {
state = {
isLoaderVisible: this.props.delay <= 0,
isLoading: true,
error: null,
response: null
}
componentDidMount() {
if (!this.state.isLoaderVisible) {
this.loaderVisibilityTimeout = setTimeout(
() => this.setState({ isLoaderVisible: true }),
this.props.delay
)
}
this.props
.fetch()
.then(response => this.setState({ response, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }))
}
componentWillUnmount() {
clearTimeout(this.loaderVisibilityTimeout)
}
loaderVisibilityTimeout = null
render() {
const { renderLoader, renderSuccess, renderError } = this.props
const { isLoaderVisible, isLoading, response, error } = this.state
if (isLoading) {
if (isLoaderVisible) {
return renderLoader()
}
return null
}
if (error) {
return renderError(error)
}
return renderSuccess(response)
}
}
Loader.defaultProps = {
delay: 0,
renderLoader: () => <div>Loading</div>,
renderError: error => (
<div data-testid="error">
<h1>Something went wrong</h1>
<p>{error.message}</p>
</div>
)
}
新版本 - 功能组件(有警告)
import React, { useEffect, useRef, useState } from 'react'
import PropTypes from 'prop-types'
import Placeholder, { ELayoutType } from './Placeholder'
let counter = 1
const Loader = ({ delay, renderLoader, renderSuccess, renderError, fetch }) => {
const [state, setState] = useState({
isLoaderVisible: delay <= 0,
isLoading: true,
error: null,
response: null
})
const loaderVisibilityTimeout = useRef(null)
const { isLoaderVisible, isLoading, response, error } = state
useEffect(() => {
if (!isLoaderVisible) {
loaderVisibilityTimeout.current = setTimeout(
() => setState({ ...state, isLoaderVisible: true }),
delay
)
}
fetch()
.then(res => setState({ ...state, response: res, isLoading: false }))
.catch(err => setState({ ...state, error: err, isLoading: false }))
return () => clearTimeout(loaderVisibilityTimeout.current)
}, [])
console.log(counter)
counter++
if (isLoading) {
if (isLoaderVisible) {
return renderLoader()
}
return null
}
if (error) {
return renderError(error)
}
return renderSuccess(response)
}
Loader.defaultProps = {
delay: 0,
renderLoader: () => <div>Loading</div>,
renderError: error => (
<div data-testid="error">
<h1>Something went wrong</h1>
<p>{error.message}</p>
</div>
)
}