简体   繁体   English

state 更改后反应不重新渲染

[英]react not rerendering after state change

I know there have been similar questions, but I have a weird issue.我知道有类似的问题,但我有一个奇怪的问题。

This is what I'm doing这就是我正在做的

import React, {useState} from 'react';
import './App.css';
import {Table, Button, InputGroup, FormControl} from 'react-bootstrap';

function App() {
  const [pons, setPons] = useState();
  const [translations, setTranslations] = useState([]);
  const [isInEditMode, setIsInEditMode] = useState(false);
  const [inputValue, setInputValue] = useState('samochod');
  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('localhost:8080/pons/', {method: 'POST', body: {content: translationsToSave}});
    if (resp.ok === true) {
      setInputValue('');
      setTranslations(null);
    }
  };

  return (
    <div className="App">
      {errors.length > 0 ? errors.map(e => <div key={e}>{e}</div>) : null}
      <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>
      <Table striped bordered hover>
        <thead>
        <tr>
          <th>Original</th>
          <th>Translation</th>
          <th>Actions</th>
        </tr>
        </thead>
        <tbody>
        {translations ? translations.map(pon => pon.roms.map(rom => rom.arabs.map(arab => arab.translations.map(translation => {
          const {source, target} = translation;
          return (
            <tr>
              <td><span dangerouslySetInnerHTML={{__html: source}}/></td>
              <td><span dangerouslySetInnerHTML={{__html: target}}/></td>
              <td>
                {
                  !translationsToSave.includes(target) ?
                    <Button onClick={() => {
                      const tmp = translationsToSave;
                      tmp.push(target);
                      setTranslationsToSave(tmp);
                    }}>
                      Add translation
                    </Button>
                    :
                    <Button
                      onClick={() => {
                        const tmp = translationsToSave;
                        tmp.splice(tmp.findIndex(elem => elem === target));
                        setTranslationsToSave(tmp);
                      }}>
                      Remove translation
                    </Button>
                }
              </td>
            </tr>
          )
        })))) : (
          <div>No translations</div>
        )}
        </tbody>
      </Table>
    </div>
  );
}

export default App;

So it's a basic app, it right now just adds and removes from an array wit setTranslationsToSave .所以它是一个基本的应用程序,它现在只是在数组中添加和删除setTranslationsToSave After I click the Add translation button the view stays the same.单击“ Add translation ”按钮后,视图保持不变。 But it refreshes when I click Enter edit mode .但是当我单击Enter edit mode时它会刷新。 Same with Remove translation .Remove translation相同。 I need to click Enter/Exit edit mode .我需要点击Enter/Exit edit mode

Hitting Translate also reloads the view.点击Translate也会重新加载视图。 So the Add/Remove translation buttons are the only ones which do not refresh the page.所以Add/Remove translation按钮是唯一不刷新页面的按钮。 Why?为什么? What am I missing?我错过了什么?

The issue is that you are mutating the satte in Add/Remove translation button, so when react check before re-rendering if the state updater was called with the same state it feels that nothing has changed as it does a reference check and ehnce doesn't trigger re-render问题是您正在更改添加/删除翻译按钮中的 satte,因此在重新渲染之前进行反应检查时,如果使用相同的 state 调用 state 更新程序,它会感觉没有任何变化,因为它进行了参考检查,因此没有t 触发重新渲染

Also while updating current state based on previous state use functional callback approach for state updater .此外,在基于以前的 state 更新当前 state 时, functional callback approach for state updater

Update your state like below如下更新您的 state

  <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>

In your Add translation click handler, you're mutating the state:在您的Add translation点击处理程序中,您正在改变 state:

<Button onClick={() => {
    // tmp is just a reference to state
    const tmp = translationsToSave;
    // You are mutating state, this will be lost
    tmp.push(target);
    setTranslationsToSave(tmp);
}}>

You should duplicate the state and add the new element:您应该复制 state 并添加新元素:

<Button onClick={() => {
    setTranslationsToSave([...translationsToSave, target]);
}}>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM