错误:尝试设置状态时重新渲染的次数过多

问题描述 投票:-1回答:1

这是我的代码:

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;

PonCard组件:

import {Button, Card} from "react-bootstrap";
import React, {useState} from "react";

export const PonCard = ({pon}) => {
  const [isFlipped, setIsFlipped] = useState(false);
  const handleClick = setIsFlipped(!isFlipped);

  return (
    <Card style={{width: '18rem'}}>
      <Card.Body>
        <Card.Title>{pon.original}</Card.Title>

        <Card.Text>
          {pon.translations.map(translation => (
            <div key={Math.random()} dangerouslySetInnerHTML={translation}/>
          ))}
        </Card.Text>
        <Button variant="primary" onClick={handleClick}>Show translations</Button>
      </Card.Body>
    </Card>
  )
};

我想做的是在安装时获取数据。我发现这是模仿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方法,这没有任何意义,因为它在安装时仅更新一次。我想念什么?

javascript reactjs
1个回答
© www.soinside.com 2019 - 2024. All rights reserved.