Реакция: Доступ к (обновленному) состоянию с помощью useState: он не обновляется внутри компонента, который его создает, но находится вне того места, где он вызывается - PullRequest
0 голосов
/ 15 января 2020

Почему у меня нет доступа к обновленному значению recipes (useState) из компонента, который его определяет?

В этом примере вы можете видеть, как невозможно получить доступ к этому значению вызывает ошибку в приложении после удаления ссылки на функцию, которую я использую для обновления состояния

=> Кодовое поле и код ниже

* Дважды нажмите <h1>, чтобы увидеть ошибка

https://codesandbox.io/s/sparkling-sea-5iqgo?fontsize=14&hidenavigation=1&theme=dark

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

export default function App() {
  const [userRecipes, setUserRecipes] = useRecipesData();

  return (
    <div className="App">
      <h1
        onClick={() => {
          userRecipes.setBookmarks("onetwothree");
        }}
      >
        Hello CodeSandbox
      </h1>
      <h2>{userRecipes.bookmarked_recipes}</h2>
    </div>
  );
}

const useRecipesData = () => {
  const [recipes, setRecipes] = useState({});

  const setBookmarks = newRecipes => {
    console.log(recipes); // is undefined !? and deletes setBookmarks
    setRecipes({
      bookmarked_recipes: newRecipes,
      setBookmarks: recipes.setBookmarks
    });
  };

  useEffect(() => {
    setRecipes({
      bookmarked_recipes: "testtesttest",
      setBookmarks: setBookmarks
    });
  }, []);

  return [recipes, setRecipes];
};

Я не понимаю, почему, если я возвращаю [recipes, setRecipes], где recipes.setBookmarks хранит ссылку на функцию, это не работает

Но если я возвращаю саму функцию (которая также является ссылкой) [recipes, setBookmarks], тогда она работает

См. этот другой кодовый блок, где он работает

https://codesandbox.io/s/red-violet-gju99?fontsize=14&hidenavigation=1&theme=dark

import React, { useEffect, useState } from "react";
import "./styles.css";

export default function App() {
  const [userRecipes, setUserRecipes] = useRecipesData();

  return (
    <div className="App">
      <h1
        onClick={() => {
          setUserRecipes("onetwothree" + Math.random());
        }}
      >
        Hello CodeSandbox
      </h1>
      <h2>{userRecipes.bookmarked_recipes}</h2>
    </div>
  );
}

const useRecipesData = () => {
  const [recipes, setRecipes] = useState({});

  const setBookmarks = newRecipes => {
    console.log(recipes); // is defined this time
    setRecipes({
      bookmarked_recipes: newRecipes,
      setBookmarks: recipes.setBookmarks
    });
  };

  useEffect(() => {
    setRecipes({
      bookmarked_recipes: "testtesttest",
      setBookmarks: setBookmarks
    });
  }, []);

  return [recipes, setBookmarks];
};

1 Ответ

1 голос
/ 15 января 2020

Все дело в контексте. Если вы поместите console.log(receipes) в useEffect и в саму функцию рендеринга, вы увидите, каков поток событий:

  1. Первый рецепт рендеринга пуст.
  2. Вызван UseEffect и помещает setBookmark в рецепт (но рецепт для setBookmark пуст)
  3. Второй рендер вызывается, и теперь у рецепта есть "testesttest", а recipe.setBookmark - это функция, в которой объект рецепта, связанный с ним, является Значение рецепта из события 1
  4. вызывается setBookmark, рецепт теперь установлен на "onetwothree", но объект рецепта пуст, поэтому мы устанавливаем setBookmark неопределенным.

вместо сохранения функция внутри состояния, вам нужно просто вызвать ее напрямую (IE возвращает setBookmark, а не setRecipes, например:

import React, { useEffect, useState } from "react";
import "./styles.css";

export default function App() {
  const [userRecipes, setBookmarks] = useRecipesData();

  return (
    <div className="App">
      <h1
        onClick={() => {
          setBookmarks("onetwothree" + Math.random());
        }}
      >
        Hello CodeSandbox
      </h1>
      <h2>{userRecipes.bookmarked_recipes}</h2>
    </div>
  );
}

const useRecipesData = () => {
  const [recipes, setRecipes] = useState({});
  const setBookmarks = newRecipes => {
    setRecipes({
      bookmarked_recipes: newRecipes,
    });
  };

  useEffect(() => {
    setRecipes({
      bookmarked_recipes: "testtesttest",
    });
  }, []);

  return [recipes, setBookmarks];
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...