Maneira correta de empurrar para a matriz de estado


122

Parece que estou tendo problemas para enviar dados para uma matriz de estado. Estou tentando conseguir desta forma:

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

Mas acredito que essa é a forma incorreta e causa problemas com mutabilidade?

Respostas:


145

Array push retorna comprimento

this.state.myArray.push('new value')retorna o comprimento da matriz estendida, em vez da própria matriz. Array.prototype.push () .

Eu acho que você espera que o valor retornado seja a matriz.

Imutabilidade

Parece que é mais o comportamento de React:

NUNCA modifique this.state diretamente, pois chamar setState () depois pode substituir a mutação que você fez. Trate this.state como se fosse imutável. React.Component .

Eu acho que você faria assim (não estou familiarizado com React):

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

1
Quando eu faço console.log(this.state.myArray), é sempre um atrás. Alguma ideia do porquê?
Si8 de

@ Si8 Bem, infelizmente não uso muito o React. Mas os documentos dizem: setState()enfileira as alterações no estado do componente e informa ao React que esse componente e seus filhos precisam ser renderizados novamente com o estado atualizado. Acho que não foi atualizado naquele momento, logo após configurá-lo. Você poderia postar um exemplo de código, onde possamos ver qual ponto você está configurando e registrando, por favor?
Márton Tamás

Obrigado pela resposta. É assíncrono, por isso não mostrará as alterações imediatamente. No entanto, setState tem um retorno de chamada que exibiu o valor correto. Obrigado novamente.
Si8

w3schools.com/jsref/jsref_concat_array.asp concatena dois arrays (não array e string), .concat('new value'); deveria ser .concat(['new value']);
Manohar Reddy Poreddy

1
@ManoharReddyPoreddy Valores não matriciais são perfeitamente válidos para o concat()método. Veja: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ( Matrizes e / ou valores para concatenar em uma nova matriz. )
Márton Tamás

176

Usando es6, pode ser feito assim:

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

Spread syntax


1
Eu fiz o mesmo, há dois casos em que meuArray pode ter valores e não terá. então nisso, se já tem valores, funciona perfeitamente bem. Mas em nenhum dado ... não atualiza o estado com 'novo valor'. Qualquer soln?
Krina Soni

Deve funcionar com qualquer array, não importa se tem valores ou não, será desestruturado de qualquer maneira. Talvez haja algo errado em outro lugar. Você poderia mostrar um exemplo do seu código?
Aliaksandr Sushkevich

oi Por favor, consulte meu comentário em @Tamas answer. Foi apenas uma amostra no console. Eu tentei meu array: [... this.state.myArray, 'novo valor'] para atualizar meu array de estado. Mas ele concatra apenas o último valor. Você poderia me dizer a solução?
Johncy

@Johncy Não tenho certeza se o seu problema está relacionado a esta pergunta, tente fazer uma pergunta separada e descrever o comportamento esperado e tentarei ajudá-lo.
Aliaksandr Sushkevich

5
De acordo com a documentação do React: "Como this.propse this.statepode ser atualizado de forma assíncrona, você não deve confiar em seus valores para calcular o próximo estado." No caso de modificar uma matriz, uma vez que a matriz já existe como uma propriedade de this.statee você precisa referenciar seu valor para definir um novo valor, você deve usar a forma de setState()que aceita uma função com o estado anterior como argumento. Exemplo: this.setState(prevState => ({ myArray: [...this.state.myArray, 'new value'] }));Veja: reactjs.org/docs/…
Bungle

103

Nunca recomendado para alterar o estado diretamente.

A abordagem recomendada em versões posteriores do React é usar uma função de atualização ao modificar estados para evitar condições de corrida:

Empurre a string para o final da matriz

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

Empurre a string para o início da matriz

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

Empurre o objeto para o final da matriz

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

Empurre o objeto para o início da matriz

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

1
Eu usei essa resposta. Também funciona para prefixar na matriz:this.setState((prevState) => ({ myArray: [values, ...prevState.myArray], }));
Gus

1
esta é uma abordagem muito melhor do que a resposta aceita e funciona da maneira que a documentação do React recomenda.
Ian J Miller

2
Definitivamente marcar isso com +1 porque as outras respostas não seguem as diretrizes mais recentes de uso de retornos de chamada em caso de mutação de estado consigo mesmo.
Matt Fletcher

como adicionar outros objetos de array em array de estado?
Chandni,

14

Você não deveria operar o estado de forma alguma. Pelo menos não diretamente. Se você quiser atualizar seu array, você vai querer fazer algo assim.

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

Trabalhar no objeto de estado diretamente não é desejável. Você também pode dar uma olhada nos ajudantes de imutabilidade do React.

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


5
Acredito que essa resposta seja a correta, embora eu gostaria de saber por que não podemos operar no estado, ou seja, por que não é desejável. Após pesquisar um pouco, encontrei o seguinte tutorial React - Why Immutability is Important , que ajudou a preencher as informações que faltavam e o tutorial também usa .slice()para criar um novo array e preservar a imutabilidade. Obrigado pela ajuda.
BebopSong

11

Você pode usar o .concatmétodo para criar uma cópia de sua matriz com novos dados:

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

Mas cuidado com o comportamento especial do .concatmétodo ao passar matrizes - [1, 2].concat(['foo', 3], 'bar')resultará em [1, 2, 'foo', 3, 'bar'].


1

Este Código funciona para mim:

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

3
Bem-vindo ao Stack Overflow! Por favor, não responda apenas com o código-fonte. Tente fornecer uma boa descrição sobre como sua solução funciona. Veja: Como escrevo uma boa resposta? . Obrigado
sɐunıɔ ןɐ qɐp

Eu tentei isso, mas sem sucesso. Aqui está o meu códigofetch(`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)}); });
henrie

e inicialmente inicializei o estado como uma matriz vazia, ou seja this.state = { reports=[] }... por favor, gostaria de saber o que estou fazendo de errado
henrie

@Hamid Hosseinpour
henrie

1

React-Native

se você também quiser que sua UI (ou seja, sua flatList) esteja atualizada, use PrevState: no exemplo abaixo, se o usuário clicar no botão, ele adicionará um novo objeto à lista (tanto no modelo quanto na UI )

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

0

Da seguinte forma, podemos verificar e atualizar os objetos

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

0

Aqui você não pode empurrar o objeto para uma matriz de estado como esta. Você pode empurrar como seu caminho na matriz normal. Aqui você deve definir o estado,

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

-1

Se você está apenas tentando atualizar o estado assim

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

Considere esta abordagem

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

Basicamente, prevState está escrevendo this.state para nós.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.