Правильный способ вставить в массив состояний


122

Кажется, у меня проблемы с отправкой данных в массив состояний. Я пытаюсь добиться этого следующим образом:

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

Но я считаю, что это неправильный способ и вызывает проблемы с изменчивостью?

Ответы:


146

Отправка массива возвращает длину

this.state.myArray.push('new value')возвращает длину расширенного массива вместо самого массива. Array.prototype.push () .

Я думаю, вы ожидаете, что возвращаемое значение будет массивом.

Неизменность

Похоже, это скорее поведение React:

НИКОГДА не изменяйте this.state напрямую, так как последующий вызов setState () может заменить произведенную вами мутацию. Относитесь к this.state как к неизменяемому. React.Component .

Думаю, вы бы сделали это так (не знаком с 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']);
Манохар Редди Поредди

1
@ManoharReddyPoreddy Значения, не являющиеся массивами, вполне допустимы для concat()метода. См .: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ( Массивы и / или значения для объединения в новый массив. )
Мартон Тамас

178

Используя es6, это можно сделать так:

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

Синтаксис распространения


1
Я сделал то же самое, есть два случая, когда myArray может иметь значения, а нет. так что, если у него уже есть значения, он работает отлично. Но нет данных ... он не обновляет состояние с "новым значением". Любой солнечный?
Krina Soni

Он должен работать с любыми массивами, независимо от того, есть ли у него значения или нет, он все равно будет деструктурирован. Может, в другом месте что-то не так. Не могли бы вы показать пример вашего кода?
Александр Сушкевич

привет, пожалуйста, обратитесь к моему комментарию под ответом @Tamas. Это был просто образец в консоли. Я попробовал myArray: [... this.state.myArray, 'новое значение'], чтобы обновить мой массив состояний. Но он объединяет только последнее значение. Не могли бы вы рассказать мне решение?
Johncy

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

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

104

Никогда не рекомендуется напрямую изменять состояние.

Рекомендуемый подход в более поздних версиях 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
Определенно +1 к этому, потому что другие ответы не соответствуют последним рекомендациям по использованию обратных вызовов, если состояние мутирует само.
Мэтт Флетчер,

как добавить другие объекты массива в массив состояний?
Чандни

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
Добро пожаловать в Stack Overflow! Пожалуйста, не отвечайте только исходным кодом. Постарайтесь дать хорошее описание того, как работает ваше решение. См .: Как мне написать хороший ответ? . Спасибо
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=[] }... пожалуйста, я хотел бы знать, что я делаю не так
Генри

@Hamid Hosseinpour
Генри

1

Реагировать-Native

если вы также хотите, чтобы пользовательский интерфейс ur (например, 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.