Правильний спосіб натиснути на масив стану


122

У мене, здається, виникають проблеми з підштовхуванням даних у масив стану. Я намагаюся досягти цього таким чином:

this.setState({ myArray: this.state.myArray.push('new value') })

Але я вважаю, що це неправильно і викликає проблеми з незмінністю?

Відповіді:


145

Натискання масиву повертає довжину

this.state.myArray.push('new value')повертає довжину розширеного масиву замість самого масиву. Array.prototype.push () .

Я думаю, ви очікуєте, що повернене значення буде масивом.

Незмінюваність

Здається, це скоріше поведінка React:

НІКОЛИ не мутуйте this.state безпосередньо, оскільки виклик setState () згодом може замінити зроблену вами мутацію. Ставтеся до цієї держави, ніби вона непорушна. Реакт.компонент .

Я думаю, ви зробили б це так (не знайоме з React):

var joined = this.state.myArray.concat('new value');
this.setState({ myArray: joined })

1
Коли я console.log(this.state.myArray)це роблю, це завжди один позаду. Будь-яка ідея чому?
— Si8

@ Si8 Ну, на жаль, я не використовую занадто багато React, на жаль. Але документи говорять: setState()додає зміни до стану компонента і повідомляє React, що цей компонент та його діти потрібно повторно відредагувати з оновленим станом. Тож я здогадуюсь, що він просто не оновлюється на той момент відразу після встановлення. Чи можете ви, будь ласка, опублікувати приклад коду, де ми можемо побачити, який момент ви встановлюєте, і введіть його, будь ласка?
— Márton Tamás

Дякуємо за відповідь. Це асинхронізація, тому він не покаже вам зміни відразу. Однак setState має зворотний виклик, який відображав правильне значення. Знову дякую.
— Si8

w3schools.com/jsref/jsref_concat_array.asp concat об'єднує два масиви (не масив і рядок), .concat('new value'); має бути .concat(['new value']);
— Manohar Reddy Poreddy

1
@ManoharReddyPoreddy Немасивні значення цілком справедливі для concat()методу. Дивіться: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ( масиви та / або значення для об'єднання в новий масив. )
— Márton Tamás

176

За допомогою es6 це можна зробити так:

this.setState({ myArray: [...this.state.myArray, 'new value'] }) //simple value
this.setState({ myArray: [...this.state.myArray, ...[1,2,3] ] }) //another array

Поширити синтаксис


1
Я зробив те ж саме, є два випадки, у myArray можуть бути значення, і це не буде. так що, якщо вона вже має значення, вона працює чудово. Але в жодних даних .. він не оновлює стан "новим значенням". Будь-який соль?
— Кріна Соні

Він повинен працювати з будь-якими масивами, неважливо, чи має він значення, чи не буде зруйнований. Можливо, в іншому місці щось не так. Чи можете ви, будь ласка, показати приклад коду?
— Олександр Сушкевич

привіт, будь ласка, зверніться до мого коментаря у відповідь @Tamas. Це був лише зразок у консолі. Я спробував myArray: [... this.state.myArray, 'нове значення'], щоб оновити масив свого стану. Але він містить лише останнє значення. Не могли б ви сказати мені рішення?
— Джонсі

@Johncy Я не впевнений, чи пов’язана ваша проблема з цим питанням, спробуйте задати окреме питання та опишіть очікувану поведінку, і я спробую вам допомогти.
— Олександр Сушкевич

5
За документами React: "Оскільки this.propsі this.stateможе бути оновлено асинхронно, ви не повинні покладатися на їх значення для обчислення наступного стану." У разі зміни масиву, оскільки масив вже існує як властивість this.stateі вам потрібно посилатися на його значення, щоб встановити нове значення, ви повинні використовувати форму, setState()яка приймає функцію з попереднім станом як аргумент. Приклад: this.setState(prevState => ({ myArray: [...this.state.myArray, 'new value'] }));Дивіться: reactjs.org/docs/…
— Bungle

103

Ніколи не рекомендується мутувати стан безпосередньо.

Рекомендований підхід у пізніших версіях React полягає у використанні функції оновлення при зміні станів для запобігання перегоновим умовам:

Натисніть рядок до кінця масиву

this.setState(prevState => ({
  myArray: [...prevState.myArray, "new value"]
}))

Натисніть рядок до початку масиву

this.setState(prevState => ({
  myArray: ["new value", ...prevState.myArray]
}))

Натисніть об’єкт до кінця масиву

this.setState(prevState => ({
  myArray: [...prevState.myArray, {"name": "object"}]
}))

Натисніть об’єкт до початку масиву

this.setState(prevState => ({
  myArray: [ {"name": "object"}, ...prevState.myArray]
}))

1
Я використав цю відповідь. Він також працює для попереднього введення в масив:this.setState((prevState) => ({ myArray: [values, ...prevState.myArray], }));
— Gus

1
це набагато кращий підхід, ніж прийнята відповідь, і робить це так, як рекомендує документація React.
— Ian J Miller

2
Однозначно + 1ing це, тому що інші відповіді не відповідають останнім вказівкам щодо використання зворотних викликів, якщо мутує стан із собою.
— Метт Флетчер

як додати ще один об’єкт масиву в масив стану?
— Чандні

14

Ви не повинні керувати державою взагалі. Принаймні, не безпосередньо. Якщо ви хочете оновити масив, ви хочете зробити щось подібне.

var newStateArray = this.state.myArray.slice();
newStateArray.push('new value');
this.setState(myArray: newStateArray);

Робота над об'єктом держави безпосередньо небажана. Ви також можете поглянути на помічників React про незмінність.

https://facebook.github.io/react/docs/update.html


5
Я вважаю, що ця відповідь є правильною, хоча я хотів би знати, чому ми не можемо діяти в державі, тобто чому це не бажано. Після невеликого копання я знайшов наступний підручник React - Чому важлива незмінність , яка допомогла заповнити відсутні дані та підручник також використовує .slice()для створення нового масиву та збереження незмінності. Дякую за допомогу.
— BebopSong

11

Ви можете використовувати .concatметод для створення копії масиву з новими даними:

this.setState({ myArray: this.state.myArray.concat('new value') })

Але остерігайтеся особливої ​​поведінки .concatметоду при передачі масивів - [1, 2].concat(['foo', 3], 'bar')це призведе до [1, 2, 'foo', 3, 'bar'].


1

Цей Кодекс працює для мене:

fetch('http://localhost:8080')
  .then(response => response.json())
  .then(json => {
  this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
})

3
Ласкаво просимо до переповнення стека! Не відповідайте лише вихідним кодом. Спробуйте надати приємний опис про те, як працює ваше рішення. Дивіться: Як написати гарну відповідь? . Дякую
— sɐunıɔ ןɐ qɐp

Я спробував це, але безрезультатно. Ось мій кодfetch(`api.openweathermap.org/data/2.5/forecast?q=${this.searchBox.value + KEY} `) .then( response => response.json() ) .then( data => { this.setState({ reports: this.state.reports.push.apply(this.state.reports, data.list)}); });
— Хенрі

і я спочатку ініціалізував стан як порожній масив, тобто this.state = { reports=[] }... pls, я хотів би знати, що я роблю неправильно
— henrie

@Hamid Hosseinpour
— henrie

1

Реакція-Рідна

якщо ви також хочете, щоб інтерфейс ур (наприклад, ur flatList) був оновлений, використовуйте PrevState: у наведеному нижче прикладі, якщо користувач натискає кнопку, він додасть новий список до списку (і в моделі, і в інтерфейсі користувача) )

data: ['shopping','reading'] // declared in constructor
onPress={() => {this.setState((prevState, props) => {
return {data: [new obj].concat(prevState.data) };
})}}. 

0

У такий спосіб ми можемо перевірити та оновити об'єкти

this.setState(prevState => ({
    Chart: this.state.Chart.length !== 0 ? [...prevState.Chart,data[data.length - 1]] : data
}));

0

Тут ви не можете натиснути об’єкт на такий масив стану. Ви можете просуватися як звичайний масив. Тут ви повинні встановити стан,

this.setState({ 
     myArray: [...this.state.myArray, 'new value'] 
})

-1

Якщо ви просто намагаєтесь так оновити стан

   handleClick() {
        this.setState(
{myprop: this.state.myprop +1}
        })
    }

Розглянемо такий підхід

   handleClick() {
        this.setState(prevState => {
            return {
                count: prevState.count + 1
            }
        })
    }

В основному prevState пише для цього this.state.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.