Состояние остается неизменным при использовании прослушивателей событий - PullRequest
1 голос
/ 01 июня 2019

https://codesandbox.io/s/state-shenanigans-mifyg

Этот пример кода немного неортодоксален, но он все еще меня озадачивает, поэтому я решил превратить его в вопрос.

Пожалуйста, откройте ссылку выше и играйтес примером.Также держите консоль открытой.

Когда форма меняется, я вызываю console.log, передавая ему состояние.Как вы можете видеть при изменении вопроса , в нем записывается правильное значение (новый вопрос с существующим ответом).

Но если вы затем измените ответ, вы обнаружите, что старый вопрос вышел из системы с новым ответом.

Я думаю, это как-то связано с замыканиями, ноЯ не мог понять это.

import * as React from "react";
import { render } from "react-dom";

import "./styles.css";

function Faq({ onChange, data }) {
  const questionRef = React.createRef<HTMLInputElement>();
  const answerRef = React.createRef<HTMLInputElement>();

  React.useEffect(() => {
    if (questionRef.current) {
      questionRef.current.addEventListener("keydown", (e: any) => {
        onChange({ ...data, question: e.target.value });
      });
    }

    if (answerRef.current) {
      answerRef.current.addEventListener("keydown", (e: any) => {
        onChange({ ...data, answer: e.target.value });
      });
    }
  }, []);

  return (
    <div>
      <input ref={questionRef} type="text" defaultValue={data.question} />
      <input ref={answerRef} type="text" defaultValue={data.answer} />
    </div>
  );
}

const App = () => {
  const [faq, setFaq] = React.useState({
    id: "1",
    question: "I am a question?",
    answer: "I am the answer!"
  });
  React.useEffect(() => {
    console.log(faq);
  }, [faq]);
  return <Faq data={faq} onChange={setFaq} />;
};

const rootElement = document.getElementById("root");
render(<App />, rootElement);

Ответы [ 2 ]

0 голосов
/ 01 июня 2019

Вам необходимо обновить данные:

import * as React from "react";
import { render } from "react-dom";

import "./styles.css";

function Faq({ onChange, data }) {
  const questionRef = React.createRef<HTMLInputElement>();
  const answerRef = React.createRef<HTMLInputElement>();

  React.useEffect(() => {
    if (questionRef.current) {
      questionRef.current.addEventListener("keydown", (e: any) => {
        onChange({ ...data, question: e.target.value });
        data.question = e.target.value;
      });
    }

    if (answerRef.current) {
      answerRef.current.addEventListener("keydown", (e: any) => {
        onChange({ ...data, answer: e.target.value });
        data.answer = e.target.value;
      });
    }
  }, []);

  return (
    <div>
      <input ref={questionRef} type="text" defaultValue={data.question} />
      <input ref={answerRef} type="text" defaultValue={data.answer} />
    </div>
  );
}

const App = () => {
  const [faq, setFaq] = React.useState({
    id: "1",
    question: "I am a question?",
    answer: "I am the answer!"
  });
  React.useEffect(() => {
    console.log(faq);
  }, [faq]);
  return <Faq data={faq} onChange={setFaq} />;
};

const rootElement = document.getElementById("root");
render(<App />, rootElement);

https://codesandbox.io/s/state-shenanigans-kupjj

0 голосов
/ 01 июня 2019

Я не уверен, что вы подразумеваете под «старым» и «новым» вопросом, поскольку есть только один вопрос. В любом случае вам не нужно использовать ссылки DOM и ручные EvenListeners в React. React был изобретен для того, чтобы справляться с подобными вещами для вас!

function Faq({ onChange, data }) {

  const handleChange = (e) => {
    console.log("the new value is")
    console.log(e.currentTarget.value)
  }

  return (
    <div>
      <input onChange={handleChange} type="text" defaultValue={data.question} />
      <input onChange={handleChange} type="text" defaultValue={data.answer} />
    </div>
  );
}
...