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


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.