Eu estou vindo do mundo angular onde eu poderia extrair lógica para um serviço / fábrica e consumi-la em meus controladores.
Estou tentando entender como conseguir o mesmo em um aplicativo React.
Digamos que eu tenho um componente que valida a entrada de senha do usuário (é forte). Sua lógica é bastante complexa, portanto, não quero escrevê-la no componente em si.
Onde devo escrever essa lógica? Em uma loja se estou usando fluxo? Ou existe uma opção melhor?
reactjs
reactjs-flux
Dennis Nerush
fonte
fonte
Respostas:
A primeira resposta não reflete o atual paradigma Container vs Presenter .
Se você precisar fazer algo, como validar uma senha, provavelmente terá uma função que faz isso. Você passaria essa função para sua visão reutilizável como suporte.
Recipientes
Portanto, a maneira correta de fazer isso é escrever um ValidatorContainer, que terá essa função como uma propriedade, e agrupar o formulário nele, passando os objetos certos para o filho. Quando se trata de sua visualização, o contêiner do validador agrupa a visualização e a visualização consome a lógica dos contêineres.
A validação pode ser feita nas propriedades do contêiner, mas se você estiver usando um validador de terceiros ou qualquer serviço de validação simples, poderá usar o serviço como uma propriedade do componente do contêiner e usá-lo nos métodos do contêiner. Eu fiz isso por componentes repousantes e funciona muito bem.
Fornecedores
Se for necessário um pouco mais de configuração, você pode usar um modelo de Provedor / Consumidor. Um provedor é um componente de alto nível que envolve em algum lugar perto e embaixo do objeto de aplicativo principal (aquele que você monta) e fornece uma parte de si mesmo ou uma propriedade configurada na camada superior à API de contexto. Em seguida, defino meus elementos de contêiner para consumir o contexto.
As relações de contexto pai / filho não precisam estar próximas uma da outra, apenas a criança precisa ser descendente de alguma forma. O Redux armazena e o React Router funcionam dessa maneira. Usei-o para fornecer um contexto de repouso para os meus contêineres de descanso (se eu não fornecer o meu).
(observação: a API de contexto é marcada como experimental nos documentos, mas acho que não é mais, considerando o que está sendo usado).
Middleware
Uma outra maneira que eu não tentei, mas vi usada, é usar o middleware em conjunto com o Redux. Você define seu objeto de serviço fora do aplicativo, ou pelo menos, superior ao repositório redux. Durante a criação da loja, você injeta o serviço no middleware e o middleware lida com as ações que afetam o serviço.
Dessa maneira, eu poderia injetar meu objeto restful.js no middleware e substituir meus métodos de contêiner por ações independentes. Eu ainda precisaria de um componente de contêiner para fornecer as ações para a camada de exibição de formulário, mas connect () e mapDispatchToProps me cobriram lá.
O novo v4 react-router-redux usa esse método para impactar o estado do histórico, por exemplo.
fonte
O problema se torna extremamente simples quando você percebe que um serviço Angular é apenas um objeto que fornece um conjunto de métodos independentes de contexto. É apenas o mecanismo DI angular que faz com que pareça mais complicado. O DI é útil, pois cuida da criação e manutenção de instâncias para você, mas você realmente não precisa dele.
Considere uma biblioteca AJAX popular chamada axios (da qual você provavelmente já ouviu falar):
Não se comporta como um serviço? Ele fornece um conjunto de métodos responsáveis por alguma lógica específica e é independente do código principal.
Seu exemplo de caso foi sobre a criação de um conjunto isolado de métodos para validar suas entradas (por exemplo, verificar a força da senha). Alguns sugeriram colocar esses métodos dentro dos componentes, o que para mim é claramente um anti-padrão. E se a validação envolver a realização e o processamento de chamadas de back-end XHR ou cálculos complexos? Você misturaria essa lógica com os manipuladores de cliques do mouse e outras coisas específicas da interface do usuário? Absurdo. O mesmo com a abordagem de contêiner / HOC. Embrulhando seu componente apenas para adicionar um método que verificará se o valor possui um dígito? Vamos.
Gostaria apenas de criar um novo arquivo chamado 'ValidationService.js' e organizá-lo da seguinte maneira:
Então no seu componente:
Use este serviço de qualquer lugar que você desejar. Se as regras de validação mudarem, você precisará se concentrar apenas no arquivo ValidationService.js.
Você pode precisar de um serviço mais complicado, que depende de outros serviços. Nesse caso, seu arquivo de serviço pode retornar um construtor de classe em vez de um objeto estático, para que você possa criar uma instância do objeto no componente. Você também pode considerar implementar um singleton simples para garantir que sempre haja apenas uma instância do objeto de serviço em uso em todo o aplicativo.
fonte
Eu precisava que alguma lógica de formatação fosse compartilhada entre vários componentes e, como desenvolvedor Angular, também naturalmente se inclinava para um serviço.
Compartilhei a lógica colocando-a em um arquivo separado
e depois importou-o como um módulo
fonte
Lembre-se de que o objetivo do React é combinar melhor as coisas que logicamente devem ser acopladas. Se você estiver criando um método complicado de "validar senha", onde deve ser acoplado?
Bem, você precisará usá-lo sempre que o usuário precisar inserir uma nova senha. Pode estar na tela de registro, na tela "esqueci a senha", na tela "administrador redefinir a senha para outro usuário" etc.
Mas em qualquer um desses casos, ele sempre estará vinculado a algum campo de entrada de texto. Então é aí que deve ser acoplado.
Crie um componente React muito pequeno que consista apenas em um campo de entrada e na lógica de validação associada. Insira esse componente em todos os formulários que desejam ter uma entrada de senha.
É essencialmente o mesmo resultado de ter um serviço / fábrica para a lógica, mas você está acoplando-o diretamente à entrada. Portanto, agora você nunca precisa dizer a essa função onde procurar sua entrada de validação, pois ela está permanentemente ligada.
fonte
Eu também vim da área Angular.js e os serviços e fábricas no React.js são mais simples.
Você pode usar funções simples ou classes, estilo de retorno de chamada e evento Mobx como eu :)
Aqui está um exemplo simples:
fonte
Mesma situação: ter realizado vários projetos Angular e mudar para o React, não ter uma maneira simples de fornecer serviços por meio do DI parece uma peça que falta (os detalhes do serviço à parte).
Usando decoradores de contexto e ES7, podemos chegar perto:
https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/
Parece que esses caras deram um passo adiante / em uma direção diferente:
http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs
Ainda parece trabalhar contra a corrente. Revisitará esta resposta em seis meses após a realização de um grande projeto React.
Edição: Voltar 6 meses depois, com um pouco mais de experiência React. Considere a natureza da lógica:
Alguns também procuram HOCs para reutilização, mas, para mim, os itens acima abrangem quase todos os casos de uso. Além disso, considere dimensionar o gerenciamento de estado usando patos para manter as preocupações separadas e centralizar a interface do usuário no estado.
fonte
Também sou da Angular e estou tentando experimentar o React, a partir de agora, uma maneira recomendada (?) Parece estar usando componentes de alta ordem :
Digamos que você tenha
input
eetextarea
gostaria de aplicar a mesma lógica de validação:Em seguida, escreva um HOC que valide e denomine o componente agrupado:
Agora esses HOCs compartilham o mesmo comportamento de validação:
Eu criei uma demonstração simples .
Editar : Outra demonstração está usando adereços para passar uma matriz de funções, para que você possa compartilhar a lógica composta por várias funções de validação entre
HOC
s, como:Edit2 : React 16.8+ fornece um novo recurso, Hook , outra boa maneira de compartilhar lógica.
https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js
fonte
HOC
, veja minha edição para outra demonstração.O serviço não se limita ao Angular, mesmo no Angular2 + ,
O serviço é apenas uma coleção de funções auxiliares ...
E há muitas maneiras de criá-los e reutilizá-los no aplicativo ...
1) Elas podem ser todas as funções separadas que são exportadas de um arquivo js, semelhante ao abaixo:
2) Também podemos usar o método factory, como com a coleção de funções ... no ES6 , pode ser uma classe e não um construtor de funções:
Nesse caso, você precisa criar uma instância com nova chave ...
Também neste caso, cada instância tem sua própria vida, portanto, tenha cuidado se quiser compartilhá-la, nesse caso, você deve exportar apenas a instância que deseja ...
3) Se sua função e utilitários não forem compartilhados, você pode até colocá-los no componente React, nesse caso, da mesma forma que no componente reage ...
4) Outra maneira de lidar com as coisas, pode ser usar o Redux , é uma loja temporária para você, portanto, se você o tiver no aplicativo React , ele poderá ajudá-lo com muitas funções de setter getter que você usa ... É como uma grande loja que mantêm o controle de seus estados e podem compartilhá-lo entre seus componentes, assim podem se livrar de muitos problemas causados por animais que usamos nos serviços ...
É sempre bom criar um código DRY e não repetir o que precisa ser usado para tornar o código reutilizável e legível, mas não tente seguir as formas angulares no aplicativo React , como mencionado no item 4, o uso do Redux pode reduzir sua necessidade de serviços e você limita a usá-los para algumas funções auxiliares reutilizáveis, como o item 1 ...
fonte
Estou na mesma bota como você. No caso mencionado, eu implementaria o componente de interface do usuário de validação de entrada como um componente React.
Concordo que a implementação da própria lógica de validação não deve (deve) ser acoplada. Portanto, eu o colocaria em um módulo JS separado.
Ou seja, para a lógica que não deve ser acoplada, use um módulo / classe JS em um arquivo separado e use require / import para desacoplar o componente do "serviço".
Isso permite injeção de dependência e teste de unidade dos dois independentemente.
fonte
ou você pode injetar a herança de classe "http" no React Component
via objeto adereços.
update:
Basta editar o React Component ReactApp assim:
fonte
Bem, o padrão mais usado para a lógica reutilizável que encontrei é escrever um gancho ou criar um arquivo utils. Depende do que você deseja realizar.
Como se você quisesse validar os dados do formulário, eu criaria um gancho personalizado chamado useForm.js e forneceria os dados do formulário e, em troca, retornaria um objeto contendo duas coisas:
Você pode definitivamente devolver mais coisas à medida que avança.
Outro exemplo seria como você deseja extrair algumas informações de um URL, então eu criaria um arquivo utils para ele contendo uma função e importaria quando necessário:
fonte