MVVM com Factory no React Native
Tags: architecture, reactnative, typescript, designpattern
Published: 2022-11-14 12:43:05

Recentemente encontrei um vídeo muito bom falando sobre [Arquitetura MVVM no React Native](https://youtu.be/RGRfXh54d9U). 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](https://github.com/ismaelsousa/mvvm-with-react-native) 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:

```tsx
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;
```tsx
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:

```ts
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.

```tsx
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.

```tsx
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.