динамически создаваемые элементы JSX с атрибутами onAction = {}, не обновляют состояние (ОНИ ПОВРЕЖДЕНЫ) - PullRequest
1 голос
/ 02 августа 2020

Рассмотрим эти две setState переменные, значения которых изменяются после успешного выполнения обещания (например, ajax вызов)

const [ajax_response,getAjax_response] = useState("awaiting response"); //This one stores the ajax call response
const [showAjax,setShowAjax] = useState([]) //This one displays it

Обещание выполняется с помощью хука useEffect, который вызывается, когда указано (в этом примере в первом рендере)

  useEffect(() => {
    fetchData().then(data => {
      //Here it stores the value in the first useState variable
      getAjax_response(data[0])

      //Here it loops throw the data and DYNAMICALLY CREATES some attributes based on the repsponse
      //In this example it just fetches a single number from the ajax call
      //And performs a loop until it reaches that (IRELEVANT)

      for (let i=0;i < data[0];i++) {
        let styled_data = <p onClick={() => console.log(ajax_response)}>{i}</p>;
        setShowAjax(prev => [...prev,styled_data])
      }
    })
  },[])

В основном, что происходит :

  • Значение, возвращаемое из обещания, устанавливается на ajax_response , предположим, что это было CAT
  • showAjax установлен как элемент JSX с атрибутом onClick={}

Проблема:

  • Если это было возвращено в нашем рендере
  return (
    <div className="App">
      <button onClick={() => console.log(ajax_response)}>THE NORMAL BUTTON</button> //Button set manually
      {showAjax} //The JSX elements set dynamically
    </div>
  );

, THE NORMAL BUTTON будет console.log() the ajax_response и получит правильный ответ

НО ДИНАМИЧЕСКИ СОЗДАННЫЕ КНОПКИ В {showAjax} console-logs только НАЧАЛЬНОЕ СОСТОЯНИЕ из ajax_response

  • , поэтому результат выглядит так
  • Генерируется внутри {showAjax}
>>> awaiting response
  • Обычная кнопка
>>> CAT

TL: DR

REACT ELEMENTS GENERAT ED ДИНАМИЧЕСКИ С АТРИБУТАМИ ONCLICK НАРУШЕНА: ОНИ НЕ ПОКАЗЫВАЮТ ОБНОВЛЕННОЕ СОСТОЯНИЕ

1 Ответ

1 голос
/ 02 августа 2020
let styled_data = <p onClick={() => console.log(ajax_response)}>{i}</p>;
setShowAjax(prev => [...prev,styled_data])

Проблема в том, что вы сохраняете элементы реакции в состоянии. Обычно это плохая идея именно из-за проблемы, с которой вы здесь столкнулись: они никогда не будут повторно отображать, и, таким образом, очень легко создавать ошибки, когда вы отображаете устаревшие данные. Функция в этом <p> закрывает значение ajax_response, которое существовало при запуске useEffect. Ie, в его закрытии есть «ожидающий ответа», и всегда будет.

Вместо этого вашим состоянием должны быть данные, необходимые для создания компонентов, а затем вы создадите компоненты при рендеринге .

for (let i=0;i < data[0];i++) {
  // Modify this to store whatever data you need. 
  // Your example only used numbers, so i replicated that, but i expect your real code needs more.
  setShowAjax(prev => [...prev, i]); 
}

//...

return (
  <div className="App">
    <button onClick={() => console.log(ajax_response)}>THE NORMAL BUTTON</button>
    {showAjax.map(value => (
      <p onClick={() => console.log(ajax_response)}>{value}</p>
    )}
  </div>
);
...