Recentemente encontrei um vídeo muito bom falando sobre Arquitetura MVVM no React Native. Realmente é um assunto que não é muito abordado na comunidade React/React-Native. O que acaba tornando o conteúdo abordado de grande importância.
Portanto, a proposta deste conteúdo é trazer um complemento sobre a abordagem do Padrão de Arquitetura MVVM utilizando o Padrão de Projeto Factory.
Diferente do MVP (Model-View-Presenter), o MVVM (Model-View-ViewModel) traz uma proposta onde deixamos o tratamento das informações para o ViewModel, um pouco parecido com o Presenter. No entanto, a grande diferença é, enquanto o Presenter do MVP conhece a View e tem o papel de "apresentar". No MVVM o ViewModel tem o papel de também conter o tratamento das informações, porém, ele não conhece a View, ocorrendo o contrário, a View conhecendo o ViewModel, ou vários ViewModel's.
Feita a introdução, vamos ao ponto que eu quero chegar. É comum "injetarmos" o ViewModel diretamente na nossa View utilizando o MVVM. E isso me incomoda um pouco, portanto, vamos utilizar o padrão de projeto Factory para desacoplarmos a implementação do ViewModel da nossa View.
Eu aproveitei o excelente conteúdo apresentado no video e fiz um fork do repositório para realizarmos as nossas alterações.
A primeira coisa a ser feita é removermos o useLoginViewModel que estava sendo usado diretamente dentro da nossa View. Como podemos ver no código abaixo:
import useLoginViewModel from './view.model';
const LoginView: React.FC = () => {
const {email, password, setEmail, setPassword, isLoading, onSubmit} =
useLoginViewModel();
};
Vamos receber o loginViewModel via props, como o useLoginViewModel retornava o tipo LoginViewModel, então a alteração será mínima. Portanto:
- Recebemos loginViewModel via props;
const LoginView: React.FC<Props> = ({loginViewModel}) => {
const {email, password, setEmail, setPassword, isLoading, onSubmit} =
loginViewModel;
};
- Agora vamos definir um tipo para o loginViewModel, como já mencionado o useLoginViewModel retornava um tipo LoginViewModel, logo:
type Props = {
loginViewModel: LoginViewModel;
};
Bem, isso feito. Vamos criar o nosso Factory que vai realizar a composição das dependências, ou seja, vamos passar o nosso loginViewModel via props para a nossa View.
import React from 'react';
import LoginView from '../../../pages/login/view';
import useLoginViewModel from '../../../pages/login/view.model';
const loginViewFactory: React.FC = () => {
const loginViewModel = useLoginViewModel();
return <LoginView loginViewModel={loginViewModel} />;
};
export default loginViewFactory;
Por fim, agora basta usar o nosso LoginFactory na raiz do App, em vez do LoginView.
import React from 'react';
import LoginFactory from './helpers/factories/login/view.factory';
const App: React.FC = () => {
return <LoginFactory />;
};
export default App;
E é isso pessoal, com essa abordagem, conseguimos desacoplar da nossa View o ViewModel, passando apenas o tipo LoginViewModel via props, deixando totalmente independente da implementação utilizando um Factory. Ah, e os testes estão passando normalmente sem necessidade de alterações.
Caso tenha interesse em ver o código: https://github.com/MarlonBeloMarques/mvvm-factory-with-react-native
Valeu galera, até a próxima.
Top comments (5)
Bacana a abordagem, porém passar os hooks diretamente para uma única view vejo que teria renders desnecessários, sempre que o loginViewModel for alterado o seu LoginView irá renderizar toda a árvore, ou seja qualquer alteração que houver do hook
Irá renderizar tudo dentro do LoginView.
Sim, realmente é um ponto a se considerar. Porém, se fossemos usar diretamente dentro da View, o impacto seria o mesmo, não? Talvez refinando melhor a ideia, acredito que chegamos em uma solução melhor.
Se for usado diretamente dentro da View dependendo de como fossse feito teriamos o mesmo problema mesmo, porém se fosse usado um useMemo por exemplo, dessa forma tendo uma única View não funcionária, pq temos uma única prop responsável por todas as props.
Exatamente, realmente é algo que pode ser investigado para ver se serial possível com essa abordagem de ViewModel.
Sim total, no nativo temos essas facilidades, talvez irá ter uma evolução no React que nos permita aplicar essas arquiteturas.