Quando usar o retorno de chamada React setState

191

Quando um estado do componente de reação é alterado, o método de renderização é chamado. Portanto, para qualquer alteração de estado, uma ação pode ser executada no corpo dos métodos de renderização. Existe um caso de uso específico para o retorno de chamada setState?

Sahil Jain
fonte
4
No momento, não está claro o que você está perguntando. Você pode incluir algum código?
Davin Tryon
2
O retorno de chamada setState é para qualquer coisa que você queira fazer depois que o estado for DEFINITELY alterado. Desde setState é assíncrona, se você quiser chamar um fx e certifique-se que o novo estado é carregado, então isso é o que o retorno de chamada é para
Jayce444
3
O caso de uso do retorno de chamada setState é bastante claro. Você a utiliza quando deseja que uma função seja executada após a atualização de um estado ESPECÍFICO. Se você colocar essa função render(), ela será executada toda vez que QUALQUER estado for atualizado, o que provavelmente não é o que você deseja. Isso também tornará seu código menos legível e lógico.
M3RS 3/04

Respostas:

222

Sim, existe, pois setStatefunciona de uma asynchronousmaneira. Isso significa que depois de ligarsetState a this.statevariável não é alterada imediatamente. portanto, se você deseja executar uma ação imediatamente após definir o estado em uma variável de estado e retornar um resultado, um retorno de chamada será útil

Considere o exemplo abaixo

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value });
  this.validateTitle();
},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

O código acima pode não funcionar como esperado, pois o title variável pode não ter sido alterada antes da validação ser executada nela. Agora você pode se perguntar se podemos realizar a validação na render()própria função, mas seria melhor e mais limpo se conseguirmos lidar com isso na própria função changeTitle, pois isso tornaria seu código mais organizado e compreensível

Nesse caso, o retorno de chamada é útil

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value }, function() {
    this.validateTitle();
  });

},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

Outro exemplo será quando você quiser dispatch e ação quando o estado for alterado. você desejará fazê-lo em um retorno de chamada, e não no modo render()como será chamado sempre que ocorrer a renderização novamente; portanto, muitos desses cenários são possíveis nos quais você precisará de retorno de chamada.

Outro caso é um API Call

Pode ocorrer um caso quando você precisar fazer uma chamada de API com base em uma alteração de estado específica; se você fizer isso no método de renderização, ela será chamada em todas as onStatealterações de renderização ou porque algum Prop passou para a Child Componentalteração.

Nesse caso, você deseja usar a setState callbackpara passar o valor do estado atualizado para a chamada da API

....
changeTitle: function (event) {
  this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
  // Call API with the updated value
}
....
Shubham Khatri
fonte
3
Eu entendo que é de natureza assíncrona. A minha pergunta era se há algo específico que apenas o callback setState pode ser usado para que talvez o corpo métodos de renderizar podem não suportar (algo além de Vamos dizer que um código melhor legibilidade.)
Sahil Jain
A validação @SahilJain é o exemplo correto, você não vai querer manipulá-la na função render () porque ela será chamada sempre que você fizer alguma alteração na renderização () que você chamaria apenas quando apenas a entrada for alterada e, portanto, na própria função #
Shubham Khatri /
A reação proíbe alterar o estado durante a renderização. Portanto, é certo colocar a validação no retorno de chamada.
Webdeb
if (this.title.length === 0) {deveria ser this.state.title.length, certo?
Dmitry Minkovsky
4
O primeiro caso de uso provavelmente não é uma boa ideia. Os retornos de chamada setState são acionados após a nova renderização; portanto, você está causando uma renderização dupla sem uma boa razão. Esse é exatamente o objetivo do argumento da função (atualizador). Você pode simplesmente executar setState(state => state.title.length ? { titleError: "Title can't be blank" } : null)e a alteração será empilhada. Não é necessário renderização dupla.
R: Esmond
46
this.setState({
    name:'value' 
},() => {
    console.log(this.state.name);
});
Araz Babayev
fonte
14
Obrigado por este trecho de código, que pode fornecer ajuda imediata e limitada. Uma explicação adequada melhoraria bastante seu valor a longo prazo , mostrando por que essa é uma boa solução para o problema e a tornaria mais útil para futuros leitores com outras perguntas semelhantes. Por favor edite sua resposta para adicionar alguma explicação, incluindo as suposições que você fez.
Machavity
1
Quando você deseja chamar uma função após a alteração do estado, pode usar o método
Araz Babayev
e se você quiser definir várias propriedades do estado, como nome, nome, etc.?
Sumanth Varada 13/08/19
44

O 1. caso de uso que me vem à cabeça é uma apichamada que não deve entrar na renderização, porque será executada para eachmudança de estado. E a chamada da API deve ser realizada apenas em alterações de estado especiais, e não em todas as renderizações.

changeSearchParams = (params) => {
  this.setState({ params }, this.performSearch)
} 

performSearch = () => {
  API.search(this.state.params, (result) => {
    this.setState({ result })
  });
}

Portanto, para qualquer alteração de estado, uma ação pode ser executada no corpo dos métodos de renderização.

Prática muito ruim , porque o rendermétodo-deve ser puro, significa que nenhuma ação, mudanças de estado, chamadas de API devem ser executadas, apenas componha sua visualização e retorne-a. As ações devem ser executadas apenas em alguns eventos. Renderizar não é um evento, mas componentDidMountpor exemplo.

webdeb
fonte
25

Considere a chamada setState

this.setState({ counter: this.state.counter + 1 })

IDÉIA

setState pode ser chamado na função assíncrona

Então você não pode confiar this. Se a chamada acima foi feita dentro de uma função assíncrona, thisela se referirá ao estado do componente naquele momento, mas esperamos que isso se refira à propriedade dentro do estado no momento em que a chamada setState ou no início da tarefa assíncrona. E, como a tarefa era assíncrona, a propriedade pode ter mudado com o tempo. Portanto, não é confiável usarthis palavra-chave para se referir a alguma propriedade do estado, portanto, usamos a função de retorno de chamada cujos argumentos são previousState e props, o que significa que quando a tarefa assíncrona foi concluída e que era hora de atualizar o estado usando a chamada setState, prevState se referirá ao estado agora quando setState ainda não começou. Garantindo a confiabilidade de que o nextState não seja corrompido.

Código errado: levaria à corrupção de dados

this.setState(
   {counter:this.state.counter+1}
 );

Código correto com setState com função de retorno de chamada:

 this.setState(
       (prevState,props)=>{
           return {counter:prevState.counter+1};
        }
    );

Portanto, sempre que precisamos atualizar nosso estado atual para o próximo estado com base no valor possuído pela propriedade agora e tudo isso está acontecendo de maneira assíncrona, é uma boa ideia usar setState como função de retorno de chamada.

Eu tentei explicá-lo em codepen aqui CODE PEN

Aniket Jha
fonte