Понимание асинхронного рендеринга React

#javascript #reactjs #rendering

#javascript #reactjs #рендеринг

Вопрос:

Я новичок в изучении React, и мне интересно, почему следующий код работает не так, как ожидалось. Я думал, что это будет отображаться, The numbers: 0123 но это только отображается 0 . Я также использовал тот же подход с компонентом на основе классов и использовал хуки, и я все еще получаю тот же результат. Чего я не понимаю в рендеринге react с использованием асинхронного кода?

 import React from "react";
import ReactDOM from "react-dom";

function App() {
  let numbers = [0];

  fetch("some.url")
    .then(res => res.json())
    .then(list => {
      for (let n of list) {
        numbers.push(n);
      }
    });

  return <div className="App">The numbers: {numbers}</div>;
}

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

Комментарии:

1. Я также создал несколько песочниц для кода, чтобы протестировать его: это для приведенного выше примера: codesandbox.io/s/nwlvnxxqkj Это классовый подход: codesandbox.io/s/wqm2z43on7 И это с использованием крючков: codesandbox.io/s/43058qw614

2. как указал @sjahan ниже, примеры состояния и перехватов не сработали, потому что я пытался загрузить незащищенный json на защищенную страницу. Обновлен для использования https, и теперь он работает!

3. Примечание стороны, вы также можете вернуть null во время загрузки вашего запроса, проверив, есть ли numbers === [0] , что-то вроде этого

Ответ №1:

Ваш код выводит 0, потому что это значение переменной number во время рендеринга.

Вы используете следующий код:

 fetch("some.url")
    .then(res => res.json())
    .then(list => {
      for (let n of list) {
        numbers.push(n);
      }
    });
  

получить новое значение асинхронно, но это не будет иметь никакого эффекта: компонент уже рендерен.

Если вы хотите обновить его, вы должны ввести свой номер переменной в state и использовать setState() для передачи нового значения.

Если вы хотите сохранить функциональные компоненты, вам следует использовать совершенно новую функцию hooks, которая должна дать вам эквивалент setState .

Комментарии:

1. Я попробовал setState подход, но получил тот же результат. Пожалуйста, посмотрите мой комментарий к исходному вопросу.

2. Это должно сработать, но ваше обещание не выполняется. Пожалуйста, исправьте свои фрагменты 😉

3. Это действительно работает. По-видимому, это заблокировало загрузку небезопасного URL, который я использовал для издевательства. Теперь я чувствую себя глупо. Спасибо!

Ответ №2:

Вы можете использовать useState перехват для создания фрагмента состояния, представляющего собой массив, и получить список чисел с помощью useEffect перехвата и обновить числа по завершении этого запроса.

Пример

 const { useState, useEffect } = React;

function getNumbers() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve([1, 2, 3, 4, 5]);
    }, 1000);
  });
}

function App() {
  const [numbers, setNumbers] = useState([0]);

  useEffect(() => {
    getNumbers().then(list => {
      setNumbers(numbers => [...numbers, ...list]);
    });
  }, []);

  return <div className="App">The numbers: {numbers.join(", ")}</div>;
}

ReactDOM.render(<App />, document.getElementById("root"));  
 <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>  

Ответ №3:

Приведенный выше фрагмент кода поможет вам понять правильное использование немого (он же без состояния) и интеллектуального (с сохранением состояния) компонента.

Начните думать об этом, используя жизненные циклы react, чтобы сделать его еще более понятным

В приведенном выше фрагменте render() уже выполнялся с начальным значением

 let numbers = [0];
  

и поскольку изменения не выполняются в состоянии или реквизитах, повторный рендеринг не происходит, и вы не получаете желаемого результата.

Решение —

  • Сделайте функциональный компонент компонентом класса, т. е. сделайте его интеллектуальным компонентом или используйте перехватчики (useState), чтобы сделать его интеллектуальным компонентом.
  • Используйте детализацию реквизитов, т. е. вычислите значение в родительском компоненте и передайте его дочернему компоненту с использованием реквизитов

Воспользуйтесь этим как возможностью подготовить свое мышление к «МЫШЛЕНИЮ в REACT»

Подробнее о Stateful vs Stateless

Ответ №4:

При создании интерфейса рендеринг является наиболее важной процедурой, с которой приходится сталкиваться программисту. Метод render) ( в React является единственным методом, необходимым в компоненте класса, и отвечает за определение вида, который будет отображаться в окне браузера. Существует множество тонкостей в том, как работает этот подход, в сочетании с продуманным способом, которым React использует свою концепцию виртуального DOM, и знание их принесло бы огромную пользу любому начинающему разработчику React. Для демонстрации обсуждаемых привычек я буду ссылаться на этот codepen. render() 101 Render) (прежде всего, не вызывается пользователем. Это часть жизненного цикла компонента React и вызывается React на разных этапах приложения, обычно при первом создании экземпляра компонента React или при новом изменении состояния компонента. Рендеринг не принимает никаких аргументов и возвращает JSX.Element, который содержит иерархию представлений текущего компонента. Эта иерархия представлений позже будет преобразована в HTML и показана в окне браузера. В рамках жизненного цикла это сценарии, в которых вызывается рендеринг:

После первого создания экземпляра компонента React, следующего за вызовом constructor(). После обновления реквизитов компонента после вызова setState() я бы порекомендовал эту статью- https://en.wikipedia.org/wiki/React_ (web_framework) сначала нужно разобраться в основах.

Ответ №5:

Это функциональный компонент, или stateless component . У него нет собственного состояния. Таким образом, если вы измените значение переменной numbers, состояние компонента не изменится. Если вы действительно хотите использовать функциональный компонент, вам следует написать логику извлечения URL-адреса и обновления состояния в родительском компоненте с отслеживанием состояния и передать numbers переменную в качестве prop компоненту без состояния.

В противном случае, если вам не нужно использовать функциональный компонент. Измените его на компонент класса и поместите переменную numbers в качестве параметра состояния и измените ее с помощью setState() метода, и все должно работать так, как ожидалось.

Я рекомендую эту статью.

Совет: Функциональный компонент теперь может изменять состояние с помощью перехватов.