Почему состояние React-приложения здесь не перерисовывается? Как получить состояние для обновления во времени - PullRequest
0 голосов
/ 09 марта 2020

Я пытаюсь выяснить, как это работает.

У меня есть переменная 'pageCounter' для отслеживания текущей страницы (обновления после предыдущего / следующего нажатия кнопки), и при ее обновлении я хочу изменить заголовок дополнительных карт на данные новой страницы.

Когда я нажимаю следующую кнопку, она не рендерится, пока я не нажму ее дважды, а в журнале консоли не будет обновлено. Но когда я нажимаю кнопку «Журнал» после нажатия кнопки «Далее», она говорит, что она обновилась?

Я провел исследование и предположил, что это связано с асинхронной c природой функции 'setState'. Однако я не уверен, как это исправить?

Я пытался поместить функцию updateTitles в ловушку useEffect, но получаю сообщение об ошибке, независимо от того, копирую ли я содержимое функции в нее или вызываю функцию внутри the hook.

Чего мне не хватает?

Ошибка при вводе содержимого updateTitles в useEffect:

Максимальное обновление Глубина превышена.

Вот код компонента: (здесь кодовая песочница)

import React from "react";
import "./styles.css";

import React, { useState, useEffect } from "react";

function Options() {
  // Component States
  const [pageCounter, setPage] = useState(1);
  const [optionTitles, setOptionTitles] = useState({
    Option1: "End of Lease Clean",
    Option2: "Regular House Cleaning",
    Option3: "Other Clean"
  });
  //Component Variables
  const pageOneTitles = {
    Option1: "End of Lease Clean",
    Option2: "Regular House Cleaning",
    Option3: "Other Clean"
  };
  const pageTwoTitles = {
    Option1: "Blah1",
    Option2: "Blah12",
    Option3: "Blah13"
  };
  const pageThreeTitles = {
    Option1: "MrMagoo",
    Option2: "Nins",
    Option3: "Pottao"
  };

  function updateTitles() {
    switch (pageCounter) {
      case 1:
        setOptionTitles(pageOneTitles);
        break;
      case 2:
        setOptionTitles(pageTwoTitles);
        break;
      case 3:
        setOptionTitles(pageThreeTitles);
        break;
      default:
        console.log("default");
        break;
    }
  }

  function nextPage() {
    if (pageCounter < 3) {
      setPage(pageCounter + 1);
      updateTitles();
      console.log(pageCounter);
    }
  }

  function prevPage() {
    if (pageCounter > 1) {
      setPage(pageCounter - 1);
      updateTitles();
      console.log(pageCounter);
    }
  }

  function printLog() {
    console.log(pageCounter);
  }

  return (
    <div id="options">
      <button onClick={prevPage} id="next">
        Back
      </button>
      <CardOption title={optionTitles.Option1} />
      <CardOption title={optionTitles.Option2} />
      <CardOption title={optionTitles.Option3} />
      <p>{}</p>
      <button onClick={nextPage} id="next">
        Next
      </button>
      <button onClick={printLog} id="next">
        log
      </button>
    </div>
  );
}
function CardOption(props) {
  return (
    <div className="card">
      <h2>{props.title}</h2>
    </div>
  );
}

export default Options;

Вот код, когда я пытаюсь использовать ловушку Вместо этого используйтеEffect, но я получаю сообщение об ошибке «Максимальная глубина обновления превышена».

        import React, { useState, useEffect } from "react";

function Options() {
  // Component States
  const [pageCounter, setPage] = useState(1);
  const [optionTitles, setOptionTitles] = useState({
    Option1: "Page 1.11",
    Option2: "Regular House Cleaning",
    Option3: "Other Clean"
  });
  //Component Variables
  const pageOneTitles = {
    Option1: "Page 1.1",
    Option2: "Regular House Cleaning",
    Option3: "Other Clean"
  };
  const pageTwoTitles = {
    Option1: "Page 2.1",
    Option2: "Blah12",
    Option3: "Blah13"
  };
  const pageThreeTitles = {
    Option1: "Page 3.1",
    Option2: "Nins",
    Option3: "Pottao"
  };

  useEffect(() => {
    switch (pageCounter) {
      case 1:
        setOptionTitles(pageOneTitles);
        break;
      case 2:
        setOptionTitles(pageTwoTitles);
        break;
      case 3:
        setOptionTitles(pageThreeTitles);
        break;
      default:
        console.log("default");
        break;
    }
  }, [pageCounter, pageOneTitles, pageTwoTitles, pageThreeTitles]);

  function nextPage() {
    if (pageCounter < 3) {
      setPage(pageCounter + 1);
      console.log(pageCounter);
    }
  }

  function prevPage() {
    if (pageCounter > 1) {
      setPage(pageCounter - 1);
      console.log(pageCounter);
    }
  }

  function printLog() {
    console.log(pageCounter);
  }

  return (
    <div id="options">
      <button onClick={prevPage} id="next">
        Back
      </button>
      <CardOption title={optionTitles.Option1} />
      <CardOption title={optionTitles.Option2} />
      <CardOption title={optionTitles.Option3} />
      <p>{pageCounter}</p>
      <button onClick={nextPage} id="next">
        Next
      </button>
      <button onClick={printLog} id="next">
        log
      </button>
    </div>
  );
}
function CardOption(props) {
  return (
    <div className="card">
      <h2>{props.title}</h2>
    </div>
  );
}

export default Options;

Вот песочница с кодом для ловушки useEffect: https://codesandbox.io/s/thirsty-panini-mkdzh

Ответы [ 3 ]

1 голос
/ 09 марта 2020

useEffect работает для каждого обновления состояния. Удостоверьтесь, чтобы установить его deps как

useEffect(()=> {
   // do stuff with pagecounter , which is updated count

},[pageCount])

Если вы хотите запустить его только один раз при монтировании

useEffect(()=> {
   // do stuff with pagecounter , which is initial count

},[])

useEffect также запускается при первом рендеринге, избегайте запуска этого при начальном рендере как

    const [pageCount, setPageCount] = useState(0)
    useEffect(()=> {
     if (pageCount===0){
       //this prevent to run on first render
       return 
     }
     // code here will only run on updating state
    },[pageCount])
0 голосов
/ 09 марта 2020

Объединение useEffect() с функцией useCallback().

  useEffect(()=> {
    updateTitles();

 },[pageCounter]);

  const updateTitles = useCallback(() => {
    switch (pageCounter) {
      case 1:
        setOptionTitles(pageOneTitles);
        break;
      case 2:
        setOptionTitles(pageTwoTitles);
        break;
      case 3:
        setOptionTitles(pageThreeTitles);
        break;
      default:
        console.log("default");
        break;
    }
  }, [pageCounter]);

Удаление функции updateTitles() из nextPage() и prevPage()

0 голосов
/ 09 марта 2020

Я думаю, что это должно работать:

import React, { useState, useEffect } from "react";

function Options() {
  // Component States
  const [pageCounter, setPage] = useState(1);
  const [optionTitles, setOptionTitles] = useState({
    Option1: "End of Lease Clean",
    Option2: "Regular House Cleaning",
    Option3: "Other Clean"
  });
  //Component Variables
  const pageOneTitles = {
    Option1: "End of Lease Clean",
    Option2: "Regular House Cleaning",
    Option3: "Other Clean"
  };
  const pageTwoTitles = {
    Option1: "Blah1",
    Option2: "Blah12",
    Option3: "Blah13"
  };
  const pageThreeTitles = {
    Option1: "MrMagoo",
    Option2: "Nins",
    Option3: "Pottao"
  };

  function updateTitles() {
    switch (pageCounter) {
      case 1:
        setOptionTitles(pageOneTitles);
        break;
      case 2:
        setOptionTitles(pageTwoTitles);
        break;
      case 3:
        setOptionTitles(pageThreeTitles);
        break;
      default:
        console.log("default");
        break;
    }
  }

  function nextPage() {
    if (pageCounter < 3) {
      setPage(prev => prev + 1, updateTitles());
      console.log(pageCounter);
    }
  }

  function prevPage() {
    if (pageCounter > 1) {
      setPage(pageCounter - 1, updateTitles());
      console.log(pageCounter);
    }
  }

  function printLog() {
    console.log(pageCounter);
  }

  return (
    <div id="options">
      <button onClick={() => prevPage() } } id="next">
        Back
      </button>
      <CardOption title={optionTitles.Option1} />
      <CardOption title={optionTitles.Option2} />
      <CardOption title={optionTitles.Option3} />
      <p>{}</p>
      <button onClick={() => { nextPage() }} id="next">
        Next
      </button>
      <button onClick={() => { printLog() }} id="next">
        log
      </button>
    </div>
  );
}
function CardOption(props) {
  return (
    <div className="card">
      <h2>{props.title}</h2>
    </div>
  );
}

export default Options;

onClick должен передать обратный вызов для вызова функции вместо ее вызова. Также я не вижу, чтобы вы использовали useEffect в коде вашего фрагмента

...