React 从 parent 监听 child 的状态

React listen to child's state from parent

该死的,两天,两个菜鸟问题,对不起大家。

昨天,我花了整个下午阅读文档,但我的 fart-ey 大脑无法处理如何使用反应挂钩将数据从 child 传递到 parent。

我想在我的 parent 上创建一个按钮,可以监听他的 child 状态以检查它并根据其值更改背景颜色。

事实是,child 组件正在映射一些东西,所以我无法创建按钮(否则它会被渲染多次,而不是像我想要的那样只渲染一次)。

我考虑过将所有数据移动到我的 parent 组件,但我无法理解如何操作,因为我是 React 的新手,而且我基本上只花了两个月的时间学习如何编写代码。

我现在将提供 parent 和 child 组件的代码。

parent :

import React from "react";
import Quizz from "./components/Quizz";

export default function App() {
  const [quizz, setQuizz] = React.useState([]);

  React.useEffect(() => {
    async function getData() {
      const res = await fetch(
        "https://opentdb.com/api.php?amount=5&category=27&type=multiple"
      );
      const data = await res.json();
      setQuizz(data.results)
    }
    getData();
  }, []);

  function checkOnChild(){ /* <== the function I'd like to use to check on my Quizz component's "activeAnswer" state */
      console.log(quizz);
  }
  
    const cards = quizz.map((item, key) => {
    return <Quizz {...item} key={key}/>;
  });
  return (
    <div>
      {cards}
      <button onClick={checkOnChild}>Check answers</button> /* <== the button that will use the function */
    </div>
  );
}

和 child :

import React from "react";
import { useRef } from "react";

export default function Quizz(props) {

  const [activeAnswer, setActiveAnswer] = React.useState('');/* <== the state I'd like to check on from my parent component */

  function toggle(answer) {
    setActiveAnswer(answer);
  }

  function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
      let j = Math.floor(Math.random() * (i + 1));
      let temp = array[i];
      array[i] = array[j];
      array[j] = temp;
    }
    return array;
  }

  let answers = props.incorrect_answers;

  const ref = useRef(false);
  if (!ref.current) {
    answers.push(props.correct_answer);

    shuffleArray(answers);
    ref.current = true;
  }

  const answerDiv = answers.map((answer, key) => (
    <div key={key} className="individuals" onClick={()=> toggle(answer)} 
    style={{background: answer == activeAnswer ? "#D6DBF5" : "transparent" }}>
    {answer}
    </div>
  ));

  console.log(answers);
  console.log(activeAnswer);
  console.log(props.correct_answer);

  return (
    <div className="questions">
      <div>
        <h2>{props.question}</h2>
      </div>
      <div className="individuals__container">{answerDiv}</div>
      <hr />
      
    </div>
   
  );
}


我真的很抱歉,如果它看起来很愚蠢或者如果我在做被禁止的事情 lmao,但在此先感谢您的帮助!

我想这应该能让你更进一步。

export default function App() {
  const [quizData, setQuizData] = useState([])
  const [quizState, setQuizState] = useState({})

  useEffect(() => {
    async function getData() {
      const res = await fetch('https://opentdb.com/api.php?amount=5&category=27&type=multiple')
      const data = await res.json()
      const results = data.results

      setQuizData(results)
      setQuizState(results.reduce((acc, curr) => ({ ...acc, [curr.question]: '' }), {}))
    }
    getData()
  }, [])

  function checkOnChild() {
    console.log(quizState)
  }

  const cards = quizData.map((item) => {
    return <Quizz {...item} key={item.question} quizState={quizState} setQuizState={setQuizState} />
  })

  return (
    <div>
      {cards}
      <button onClick={checkOnChild}>Check answers</button>
    </div>
  )
}
export default function Quizz(props) {
  function handleOnClick(answer) {
    props.setQuizState(prevState => ({
      ...prevState,
      [props.question]: answer,
    }))
  }

  const answers = useMemo(() => {
    const arr = [...props.incorrect_answers, props.correct_answer]
    return shuffleArray(arr)
  }, [props.incorrect_answers, props.correct_answer])

  const answerDiv = answers.map((answer) => (
    <div
      className="individuals"
      key={answer}
      onClick={() => handleOnClick(answer)}
      style={{ background: answer == props.quizState[props.question] ? '#D6DBF5' : 'transparent' }}
    >
      {answer}
    </div>
  ))

  return (
    <div className="questions">
      <div>
        <h2>{props.question}</h2>
      </div>
      <div className="individuals__container">{answerDiv}</div>
      <hr />
    </div>
  )
}