Javascript 错误:尝试设置状态时重新渲染过多
这是我的代码:Javascript 错误:尝试设置状态时重新渲染过多,javascript,reactjs,Javascript,Reactjs,这是我的代码: import React, {useState, useEffect} from 'react'; import './App.css'; import {Table, Button, InputGroup, FormControl} from 'react-bootstrap'; import {PonCard} from "./components/PonCard"; function App() { const [pons, setPons] = useState(n
import React, {useState, useEffect} from 'react';
import './App.css';
import {Table, Button, InputGroup, FormControl} from 'react-bootstrap';
import {PonCard} from "./components/PonCard";
function App() {
const [pons, setPons] = useState(null);
const [translations, setTranslations] = useState(null);
const [isInEditMode, setIsInEditMode] = useState(false);
const [inputValue, setInputValue] = useState('');
const [errors, setErrors] = useState([]);
const [translationsToSave, setTranslationsToSave] = useState([]);
const changeIsInEditMode = () => setIsInEditMode(!isInEditMode);
const handleEditButtonClick = (id) => console.log('Edit', id);
const handleDeleteButtonClick = (id) => console.log('Delete', id);
const handleInputChange = (e) => setInputValue(e.target.value);
const handleFetchOnButtonClick = async () => {
const resp = await fetch(`http://localhost:8080/pons/findTranslation/${inputValue}`).then(r => r.json()).catch(e => console.log(e));
if (resp.ok === true) {
setTranslations(resp.resp[0].hits);
setErrors([]);
} else {
setErrors(resp.errors ? resp.errors : ['Something went wrong. check the input']);
}
};
const handleSaveTranslations = async () => {
const resp = await fetch('http://localhost:8080/pons/', {
method: 'POST',
body: JSON.stringify({original: inputValue, translations: translationsToSave}),
mode: 'cors',
headers: {
'Content-Type': 'application/json',
}
}).then(r => r.json())
.catch(e => {
console.log(e);
return {ok: false};
});
setInputValue('');
setTranslations(null);
if (resp.errors) {
setErrors(resp.errors);
}
};
useEffect(() => {
fetch('http://localhost:8080/pons/')
.then(r => r.json())
.then(resp => {
if (resp.ok === true) {
setPons(resp.pons);
} else {
setErrors(resp.errors);
}
})
.catch(e => console.log(e));
}, []);
return (
<div className="App">
<InputGroup className="mb-3">
<FormControl
value={inputValue}
onChange={handleInputChange}
placeholder={inputValue}
/>
</InputGroup>
<div className="mb-3">
<Button onClick={handleFetchOnButtonClick} disabled={inputValue === '' || errors.length > 0}>Translate</Button>
<Button onClick={changeIsInEditMode}>
{isInEditMode ? 'Exit edit mode' : 'Enter edit mode'}
</Button>
<Button disabled={translationsToSave.length === 0} onClick={handleSaveTranslations}>Save translations</Button>
</div>
{errors.length > 0 ? errors.map(e => <div key={e}>{e}</div>) : null}
{
pons && !translations && inputValue === '' ? pons.map(pon => <PonCard key={Math.random()} {...{pon}}/>) : null
}
{
translations ?
<Table striped bordered hover>
<thead>
<tr>
<th>Original</th>
<th>Translation</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{
translations.map(pon => pon.roms.map(rom => rom.arabs.map(arab => arab.translations.map(translation => {
const {source, target} = translation;
return (
<tr key={Math.random()}>
<td><span dangerouslySetInnerHTML={{__html: source}}/></td>
<td><span dangerouslySetInnerHTML={{__html: target}}/></td>
<td>
{
!translationsToSave.includes(target) ?
<Button onClick={() => {
setTranslationsToSave(prev => [...prev, target]);
}}>
Add translation
</Button>
:
<Button
onClick={() => {
setTranslationsToSave((prev) => {
const index = prev.findIndex(elem => elem === target)
return [...prev.slice(0, index), ...prev.slice(index + 1)]
});
}}>
Remove translation
</Button>
}
</td>
</tr>
)
}))))
}
</tbody>
</Table>
: (
<span>No translations</span>
)
}
</div>
);
}
export default App;
我要做的是获取挂载上的数据。我发现这是模仿componentDidMount
useEffect(() => {
fetch('http://localhost:8080/pons/')
.then(r => r.json())
.then(resp => {
if (resp.ok === true) {
setPons(resp.pons);
} else {
setErrors(resp.errors);
}
})
.catch(e => console.log(e));
}, []);
但我明白了
错误:重新渲染过多。React限制渲染的数量以防止无限循环
一直如此
106 | .then(r => r.json())
107 | .then(resp => {
108 | if (resp.ok === true) {
> 109 | setPons(resp.pons);
| ^ 110 | } else {
111 | setErrors(resp.errors);
112 | }
它指向
setPons
方法,这没有意义,因为它在装载时只更新一次。我遗漏了什么?问题是PonCard中的这一行:
const handleClick = setIsFlipped(!isFlipped);
每次PonCard渲染时,该行将立即切换其翻转状态,从而再次渲染并再次翻转,依此类推。您可能打算这样做:
const handleClick = () => setIsFlipped(!isFlipped);
错误消息指向setPons
的原因只是因为这是启动它的第一个设置状态。在此之前,没有渲染PonCard,因此没有无限循环的PonCard渲染
const handleClick = () => setIsFlipped(!isFlipped);