Я изучаю 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>
)
}
}
Я ожидал, что компоненты будут увеличивать свои значения, и они это сделали, но они не обновляются в браузере.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Ну, в этом коде так много всего неправильного. Начнем с простого, импорт компонента 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. Поэтому мне нужно что-то, где я указываю количество компонентов счетчика, которые я хочу отобразить. Большое спасибо еще раз.
@RobertoDieguez Тогда делайте это, как и раньше, но переместите весь компонентWillMount в componentDidUpdate. ComponentDidUpdate запускается каждый раз, когда вы изменяете/обновляете состояние, componentWillMount только один раз при создании компонента.
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 небезопасным, тем больше причин не использовать его, и если вы считаете, что он вам действительно нужен, используйте конструктор.
Подробнее см. документы.
Привет, добро пожаловать в переполнение стека. Хороший ответ; но поместите основные части вашего кода в сам ответ, а не в виде гиперссылки; это может стать недействительным, если связанная страница изменится.
ComponentWillMount запускает код перед монтированием приложения, т.е. (до вызовов функции рендеринга). Это не предлагается реагировать, поскольку это небезопасно. Вот рабочий URL: stackblitz.com/edit/react-p9i5nt