Eu tenho lido um monte de react
código e vejo coisas assim que não entendo:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
Eu tenho lido um monte de react
código e vejo coisas assim que não entendo:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
Respostas:
Essa é uma função ao curry
Primeiro, examine esta função com dois parâmetros…
Aqui está novamente em forma de curry…
Aqui está o mesmo código 1 sem funções de seta…
Focar em
return
Pode ajudar a visualizá-lo de outra maneira. Sabemos que as funções de seta funcionam assim - vamos prestar especial atenção ao valor de retorno .
Portanto, nossa
add
função retorna uma função - podemos usar parênteses para maior clareza. O texto em negrito é o valor de retorno da nossa funçãoadd
Em outras palavras,
add
de algum número retorna uma funçãoChamando funções com caril
Então, para usar nossa função ao curry, precisamos chamá-la de um jeito diferente…
Isso ocorre porque a primeira chamada de função (externa) retorna uma segunda função (interna). Somente depois que chamamos a segunda função é que obtemos o resultado. Isso é mais evidente se separarmos as chamadas em duas linhas ...
Aplicando nosso novo entendimento ao seu código
OK, agora que entendemos como isso funciona, vejamos seu código
Começaremos por representá-lo sem usar as funções de seta ...
No entanto, porque as funções de seta lexically ligamento
this
, seria realmente se parecem mais com isso ...Talvez agora possamos ver o que isso está fazendo com mais clareza. A
handleChange
função está criando uma função para um especificadofield
. Esta é uma técnica útil do React, pois você precisa configurar seus próprios ouvintes em cada entrada para atualizar o estado dos aplicativos. Usando ahandleChange
função, podemos eliminar todo o código duplicado que resultaria na configuração dechange
listeners para cada campo. Legal!1 Aqui não tive que ligar lexicamente
this
porque aadd
função original não usa nenhum contexto; portanto, não é importante preservá-la neste caso.Ainda mais flechas
Mais de duas funções de seta podem ser sequenciadas, se necessário -
Funções curry são capazes de coisas surpreendentes. Abaixo, vemos
$
definida como uma função ao curry com dois parâmetros, mas no site da chamada, parece que podemos fornecer qualquer número de argumentos. Currying é a abstração da aridade -Aplicação parcial
Aplicação parcial é um conceito relacionado. Ele nos permite aplicar parcialmente funções, semelhantes ao curry, exceto que a função não precisa ser definida na forma de caril -
Aqui está uma demonstração funcional sobre a qual
partial
você pode jogar em seu próprio navegador -fonte
$
foi usado para demonstrar o conceito, mas você pode chamá- lo como quiser. Coincidentemente, mas completamente independente,$
tem sido usado em bibliotecas populares como o jQuery, onde$
é uma espécie de ponto de entrada global para toda a biblioteca de funções. Eu acho que tem sido usado em outros também. Outro que você verá é_
popularizado em bibliotecas como sublinhado e lodash. Nenhum símbolo é mais significativo que outro; você atribui o significado ao seu programa. É simplesmente válido JavaScript: D$
olhando para como é usado. Se você está perguntando sobre a implementação em si,$
é uma função que recebe um valorx
e retorna uma nova funçãok => ...
. Olhando para o corpo da função retornada, vemosk (x)
quek
também sabemos que deve ser uma função, e qualquer que seja o resultadok (x)
é devolvido ao$ (...)
que sabemos que devolve outrak => ...
, e continua ... Se você ainda está ficar preso, me avise.abc(1,2,3)
é menos do que o idealabc(1)(2)(3)
. É mais difícil argumentar sobre a lógica do código, é difícil ler a função abc e é mais difícil ler a chamada de função. Antes que você só precisasse saber o que o abc faz, agora você não tem certeza do que as funções não nomeadas que o abc está retornando fazem e duas vezes.Compreender as sintaxes disponíveis das funções de seta fornecerá uma compreensão de qual comportamento elas estão apresentando quando encadeadas, como nos exemplos que você forneceu.
Quando uma função de seta é gravada sem chaves, com ou sem vários parâmetros, a expressão que constitui o corpo da função é retornada implicitamente . No seu exemplo, essa expressão é outra função de seta.
Outra vantagem de escrever funções anônimas usando a sintaxe da seta é que elas estão ligadas lexicamente ao escopo em que são definidas. Nas 'Funções da seta' no MDN :
Isso é particularmente pertinente no seu exemplo, considerando que é retirado de um reactjsinscrição. Como apontado por @naomik, no React você costuma acessar as funções de membro de um componente usando
this
. Por exemplo:fonte
Uma dica geral, se você ficar confuso com alguma sintaxe JS nova e como ela será compilada, verifique babel . Por exemplo, copiar seu código em babel e selecionar a predefinição es2015 fornecerá uma saída como esta
fonte
Pense assim, toda vez que vir uma seta, substitua-a por
function
.function parameters
são definidos antes da seta.Então, no seu exemplo:
e depois juntos:
Dos documentos :
fonte
this
.Breve e simples 🎈
É uma função que retorna outra função escrita de maneira abreviada.
Por que as pessoas fazem isso ?
Você já enfrentou quando precisa escrever uma função que pode ser personalizada? Ou você precisa escrever uma função de retorno de chamada que tenha parâmetros fixos (argumentos), mas precisa passar mais variáveis para a função, evitando variáveis globais? Se sua resposta for " sim ", é assim que se faz.
Por exemplo, temos um
button
retorno de chamada onClick. E precisamos passarid
para a função, masonClick
aceita apenas um parâmetroevent
, não podemos passar parâmetros extras dentro desta:Isso não vai funcionar!
Portanto, criamos uma função que retornará outra função com seu próprio escopo de variáveis sem nenhuma variável global, porque as variáveis globais são más 😈.
Abaixo a função
handleClick(props.id)}
será chamada e retornará uma função e ela teráid
em seu escopo! Não importa quantas vezes seja pressionado, os IDs não se afetam ou se alteram, eles são totalmente isolados.fonte
O exemplo na sua pergunta é o de um
curried function
que faz usoarrow function
e possui umimplicit return
para o primeiro argumento.A função Arrow lexicamente liga isso, ou seja, eles não têm seu próprio
this
argumento, mas recebem othis
valor do escopoUm equivalente do código acima seria
Mais uma coisa a observar sobre o seu exemplo é que define
handleChange
como uma const ou uma função. Provavelmente você o está usando como parte de um método de classe e ele usa umclass fields syntax
então, em vez de vincular a função externa diretamente, você a vincularia no construtor da classe
Outra coisa a observar no exemplo é a diferença entre retorno implícito e explícito.
Acima está um exemplo de retorno implícito, ie. pega o campo de valor como argumento e retorna o resultado
field*2
que especifica explicitamente a função a ser retornadaPara um retorno explícito, você explicitamente diria ao método para retornar o valor
Outra coisa a ser observada sobre as funções das setas é que elas não têm suas próprias
arguments
mas herdam isso também do escopo dos pais.Por exemplo, se você apenas definir uma função de seta como
Como uma seta alternativa, as funções fornecem os demais parâmetros que você pode usar
fonte
Pode não estar totalmente relacionado, mas como a pergunta mencionada reage ao caso de uso (e eu continuo colidindo com esse segmento SO): Há um aspecto importante da função de seta dupla que não é explicitamente mencionado aqui. Somente a 'primeira' seta (função) é nomeada (e, portanto, 'distinguível' pelo tempo de execução); quaisquer setas a seguir são anônimas e, do ponto de vista do React, são contadas como um 'novo' objeto em cada renderização.
Portanto, a função de seta dupla fará com que qualquer PureComponent seja renderizado o tempo todo.
Exemplo
Você tem um componente pai com um manipulador de alterações como:
e com uma renderização como:
{ tasks.map(task => <MyTask handleChange={this.handleChange(task)}/> }
handleChange então usado em uma entrada ou clique. E tudo isso funciona e parece muito bom. MAS significa que qualquer alteração que faça com que o pai seja renderizado novamente (como uma mudança de estado completamente não relacionada) também renderizará TODAS o seu MyTask, mesmo que sejam PureComponents.
Isso pode ser aliviado de várias maneiras, como passar a seta 'mais distante' e o objeto com o qual você a alimentaria ou escrever uma função shouldUpdate personalizada ou voltar ao básico, como escrever funções nomeadas (e vincular isso manualmente ...)
fonte