React js не обновляет массив JSX

Я изучаю React уже 2 недели и сейчас пытаюсь понять, как работает Lifting State Up. В этом коде я пытаюсь сделать простой счетчик, вы нажимаете кнопку уменьшения или увеличения, и я обновляю состояние с помощью этой функции, называемой handleButtons. Я обрабатываю свой объект состояния в своем основном файле «App.js», потому что таким образом я могу использовать столько компонентов «Счетчик», сколько захочу, и они имеют одно и то же состояние, поэтому я могу обновлять все счетчики с помощью одной кнопки. Я использовал функцию «componentWillMount», чтобы создать массив компонентов «Счетчик» и показать его в моей функции рендеринга. Проблема в том, что когда я нажимаю на одну из этих кнопок, ничего не происходит. Состояние обновляется (я вижу его на консоли), но компоненты счетчика по-прежнему показывают «0» на веб-странице.

Это мой файл App.js

import React from 'react';
import './App.css';
import {Counter} from './components/Counter';


class App extends React.Component{

  state = {
    count: 0
  }

  counters = []

  handleButtons = (event) => {
    if (event.target.name === 'increment'){
      this.setState({
        count: this.state.count + 1
      }) 
    }else if (event.target.name === 'decrement'){
      this.setState({
        count: this.state.count - 1
      })
    }
    console.info(this.state.count)
  }

  componentWillMount(){
    for(let i = 0; i< 10;i++){
      this.counters.push(<div key = {i}><Counter count = {this.state.count}/><br/></div>)
    }
  }

  render(){
    return(
      <div className = 'App'>
        {this.counters}
        <button className = 'Button' name = 'increment' onClick = {this.handleButtons}>Increment</button><br/><br/>
        <button className = 'Button' name = 'decrement' onClick = {this.handleButtons}>Decrement</button>

      </div>
    );
  }

}

export default App;

и это мой файл Counter.js

import React from 'react';

export class Counter extends React.Component{
    render(){
        return(
            <div className = 'App'>
                {this.props.count}
            </div>
        )
    }
}

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

ComponentWillMount запускает код перед монтированием приложения, т.е. (до вызовов функции рендеринга). Это не предлагается реагировать, поскольку это небезопасно. Вот рабочий URL: stackblitz.com/edit/react-p9i5nt

Shubham Verma 28.06.2019 21:12
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
952
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ну, в этом коде так много всего неправильного. Начнем с простого, импорт компонента React:

componentWillMount(){
    for(let i = 0; i< 10;i++){
      this.counters.push(<div key = {i}><Counter count = {this.state.count}/><br/></div>)
    }
  }

Это неправильно, вы не используете такие компоненты (вы можете, но это не то, как его нужно использовать), компонент используется внутри функции рендеринга следующим образом:

render(){
 return(
  <div className = 'App'>
    <Counter count = {this.state.count} /> //this line right here is the important
    <button className = 'Button' name = 'increment' onClick = {this.handleButtons}>Increment</button><br/><br/>
    <button className = 'Button' name = 'decrement' onClick = {this.handleButtons}>Decrement</button>
  </div>
 );
}

Обратите внимание, что мы удалили тот странный массив, который у вас был, и мы использовали импортированный компонент Counter, также обратите внимание, что мы добавили атрибут (prop в jsx), который равен счетчику в этом состоянии.

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

Тогда мой совет: удалить весь компонентWillMount(), так как теперь он бесполезен, а также удалите свойство counters = [] родительского класса.

Также обратите внимание, что ComponentWillMount() только при создании компонента, если вы хотите сделать это таким образом, вам нужно использовать КомпонентDidUpdate(), который выполняется каждый раз, когда вы мутируете состояние.

Спасибо за Ваш ответ. Но что произойдет, если я захочу использовать больше компонентов счетчика? Например, прямо сейчас я хотел бы отобразить 10 компонентов счетчика, но, возможно, в будущем я захочу отрисовать 20. Поэтому мне нужно что-то, где я указываю количество компонентов счетчика, которые я хочу отобразить. Большое спасибо еще раз.

Roberto Dieguez 28.06.2019 21:18

@RobertoDieguez Тогда делайте это, как и раньше, но переместите весь компонентWillMount в componentDidUpdate. ComponentDidUpdate запускается каждый раз, когда вы изменяете/обновляете состояние, componentWillMount только один раз при создании компонента.

Josep Vidal 28.06.2019 21:20

componentWillMount не подходит в вашем случае. Вы можете использовать функцию arrow, чтобы показать.

// prepare counters items to render
  renderCounters = () => {
    const { count } = this.state;
    let counters = [];
    for(let i = 0; i< 10;i++){
      counters.push(<div key = {i}><Counter count = {count}/></div>);
    }
    return counters;
  }
...
// render function
  render(){
    return(
      <div className = 'App'>
        {this.renderCounters()}
        <button className = 'Button' name = 'increment' onClick = {this.handleButtons}>Increment</button><br/><br/>
        <button className = 'Button' name = 'decrement' onClick = {this.handleButtons}>Decrement</button>

      </div>
    );
  }

Когда значение состояния каким-либо образом изменяется, компонент будет автоматически перерисовываться. Это означает, что функция render вызывается. Вам не нужно беспокоиться о подготовке компонентов для отображения в функции render. Но вы не должны вызывать setState в render функции.

Если у вас есть массив для рендеринга, вы можете использовать функцию map в функции arrow или функцию render напрямую.

Давайте представим, что у вас есть массив, который нужно показать как «myCounters»,

// render function

  render(){
    const { myCounters } = this.state;
    return(
      <div className = 'App'>
        {myCounters.map((item, index) => 
             <div key = {index}>
                 <Counter count = {item.count}/>
             </div>)
        }
        <button className = 'Button' name = 'increment' onClick = {this.handleButtons}>Increment</button><br/><br/>
        <button className = 'Button' name = 'decrement' onClick = {this.handleButtons}>Decrement</button>
      </div>
    );
  }

Мне очень нравится этот вопрос, поскольку вы наткнулись на крайний случай, о котором я до сих пор не думал.

По сути, это происходит потому, что вы добавляете компоненты в список, который не находится в состоянии в вашей функции componentWillMount. Эти компоненты «счетчика» на самом деле не будут обновляться и будут удалены из жизненного цикла компонента.

Все, что вам нужно сделать, это убедиться, что эти счетчики добавлены в жизненный цикл. Вы делаете это, определяя список и отображая его в своей функции рендеринга. Посмотреть здесь: Рендеринг array.map() в React

Надеюсь, это поможет!

Ответ принят как подходящий

Я уже вижу некоторые ответы, однако я также хочу уточнить проблему и добавить поверх других ответов, поскольку вы начинаете с React. Понимание проблемы — первый и самый важный шаг в обучении:

Проблема: Вы использовали метод жизненного цикла componentWillMount, который запускается во время монтирования, то есть при запуске, и генерирует массив счетчиков с использованием цикла. Теперь ваш список счетчиков имеет зависимость от состояния, которая разрешается в методе жизненного цикла только один раз с начальным значением 0. Почему? componentWillMount предназначен для запуска только один раз, поэтому, когда ваше состояние обновляется, оно не влияет ни на что в componentWillMount или на входы вашего списка Counter. Вот почему все, что нужно отобразить, должно быть в функции рендеринга или вызываться из функции рендеринга, а не связано с методами жизненного цикла.

Решение: Вам не нужно генерировать его в componentWillMount. Его можно просто обработать в методе render, и, поскольку вы будете определять зависимость state в методе рендеринга, React позаботится о том, чтобы всякий раз при обновлении состояния обновлялся ваш список счетчиков.

Хватит болтать, покажи код: Фрагмент кода ниже будет вашей новой функцией рендеринга, и вы можете безопасно удалить componentWillMount, хотя вы можете создать список в нескольких стилях, но я беру на себя инициативу здесь.

render() {
    let counterList = [];
    for (let i = 0; i < 10; i++) {
      counterList.push(
        <div key = {i}>
          <Counter count = {this.state.count} />
          <br />
        </div>
      );
    }

    return (
      <div className = "App">
        {counterList}
        <button
          className = "Button"
          name = "increment"
          onClick = {this.handleButtons}
        >
          Increment
        </button>
        <br />
        <br />
        <button
          className = "Button"
          name = "decrement"
          onClick = {this.handleButtons}
        >
          Decrement
        </button>
      </div>
    );
  }
}

См. рабочий код здесь.

Отдельно React объявил componentWillMount небезопасным, тем больше причин не использовать его, и если вы считаете, что он вам действительно нужен, используйте конструктор.

Подробнее см. документы.

Привет, добро пожаловать в переполнение стека. Хороший ответ; но поместите основные части вашего кода в сам ответ, а не в виде гиперссылки; это может стать недействительным, если связанная страница изменится.

Jeroen Heier 28.06.2019 22:14

Другие вопросы по теме