O autor do material, cuja tradução publicamos hoje, diz que ele faz parte da equipe do
Hike messenger, que está envolvida em novos recursos do aplicativo. O objetivo dessa equipe é traduzir em realidade e explorar idéias de que os usuários possam gostar. Isso significa que os desenvolvedores precisam agir rapidamente e que frequentemente precisam fazer alterações nas inovações que estão pesquisando, que visam tornar a experiência do usuário o mais conveniente e agradável possível. Eles preferem conduzir seus experimentos usando o React Native, pois essa biblioteca acelera o desenvolvimento e permite que você use o mesmo código em plataformas diferentes. Além disso, eles usam a biblioteca Redux.

Quando os desenvolvedores da Hike começam a trabalhar em algo novo, quando discutem a arquitetura da solução investigada, eles têm várias perguntas:
- Esta é uma oportunidade experimental que pode, como se costuma dizer, "não voar", e terá que ser abandonada. Diante disso, é necessário gastar tempo projetando a arquitetura do aplicativo?
- Um aplicativo experimental é apenas um MVP, um produto minimamente viável, com 1-2 telas e precisa ser criado o mais rápido possível. Diante disso, devo entrar em contato com o Redux?
- Como você justifica o tempo que leva para que os gerentes de produto preparem a infraestrutura de suporte para um aplicativo experimental?
De fato, o Redux ajuda você a encontrar as respostas certas para todas essas perguntas. A arquitetura Redux ajuda a separar o estado do aplicativo do React. Permite criar um repositório global localizado no nível superior do aplicativo e fornecer acesso de estado para todos os outros componentes.
Separação de responsabilidades
O que é uma "separação de responsabilidades"? É o que a
Wikipedia diz sobre isso: “Na ciência da computação, a divisão de responsabilidades é o processo de dividir um programa de computador em blocos funcionais que se sobrepõem o menos possível às funções um do outro. Em um caso mais geral, a divisão de responsabilidades é a simplificação de um único processo para resolver um problema, dividindo-o em processos de interação para resolver subtarefas ".
A arquitetura do Redux permite implementar o princípio da separação de responsabilidades nos aplicativos, dividindo-os em quatro blocos, mostrados na figura a seguir.
Arquitetura ReduxAqui está uma breve descrição desses blocos:
- Representações ou componentes da interface do usuário (Componentes da interface do usuário) se assemelham a funções puras (ou seja, funções que não alteram os dados transferidos para eles e têm algumas outras propriedades) que são responsáveis por exibir informações na tela com base nos dados transferidos para ela da loja. Eles não alteram dados diretamente. Quando um evento ocorre, ou se o usuário interage com eles, eles recorrem aos criadores das ações.
- Os criadores de ação são responsáveis por criar e despachar ações.
- Os redutores recebem ações agendadas e atualizam o estado do repositório.
- O Data Store é responsável por armazenar dados do aplicativo.
Considere a arquitetura do Redux como um exemplo.
E se diferentes componentes precisarem dos mesmos dados?
O aplicativo Caminhada tem uma tela exibindo a lista de amigos do usuário. As informações sobre sua quantidade são exibidas na parte superior desta tela.
Tela de amigos no aplicativo CaminhadaExistem 3 componentes do React aqui:
FriendRow
é um componente que contém o nome do amigo do usuário e algumas outras informações sobre ele.FriendsHeader
- um componente que exibe a inscrição "MEUS AMIGOS" e informações sobre o número de amigos.ContainerView
é um componente de contêiner que combina o título da tela representado pelo componente FriendsHeader
e a lista de amigos obtida ao percorrer uma matriz que contém informações sobre os amigos do usuário, cada elemento exibido na tela pelo componente FriendRow
.
Aqui está o código para
friendsContainer.js para ilustrar o acima:
class Container extends React.Component { constructor(props) { super(props); this.state = { friends: [] }; } componentDidMount() { FriendsService.fetchFriends().then((data) => { this.setState({ friends: data }); }); } render() { const { friends } = this.state; return ( <View style={styles.flex}> <FriendsHeader count={friends.length} text='My friends' /> {friends.map((friend) => (<FriendRow {...friend} />)) } </View> ); } }
Uma maneira completamente óbvia de criar uma página de aplicativo é carregar dados sobre amigos em um componente de contêiner e passá-los como propriedades para componentes filho.
Vamos pensar no fato de que esses dados sobre amigos podem ser necessários em alguns outros componentes usados no aplicativo.
Caminhada na tela de bate-papoSuponha que o aplicativo tenha uma tela de bate-papo, que também contém uma lista de amigos. Pode-se observar que os mesmos dados são usados na tela com a lista de amigos e na tela de bate-papo. O que fazer em uma situação semelhante? Temos duas opções:
- Você pode fazer o download dos dados do seu amigo novamente no componente
ComposeChat
, responsável por exibir as listas de bate-papo. No entanto, essa abordagem não é particularmente boa, pois seu uso significa duplicação de dados e pode levar a problemas com a sincronização. - Você pode baixar dados sobre amigos em um componente de nível superior (o contêiner principal do aplicativo) e transferir esses dados para os componentes responsáveis por exibir uma lista de amigos e listar salas de bate-papo. Além disso, precisamos passar funções para esses componentes para atualizar os dados de amigos, o que é necessário para oferecer suporte à sincronização de dados entre os componentes. Essa abordagem levará ao fato de que o componente de nível superior será literalmente compactado com métodos e dados que ele não usa diretamente.
Ambas as opções não são tão atraentes. Agora vamos ver como nosso problema pode ser resolvido usando a arquitetura Redux.
Usando Redux
Aqui estamos falando sobre a organização do trabalho com dados usando armazenamento, criadores de ação, redutores e dois componentes da interface do usuário.
▍1 Data warehouse
O repositório contém dados carregados sobre os amigos do usuário. Esses dados podem ser enviados para qualquer componente, caso necessário.
§ 2 Criadores de ação
Nesse caso, o criador da ação é usado para despachar eventos destinados a salvar e atualizar dados sobre amigos. Aqui está o código para
friendsActions.js :
export const onFriendsFetch = (friendsData) => { return { type: 'FRIENDS_FETCHED', payload: friendsData }; };
▍3 Redutores
Os redutores aguardam a chegada de eventos que representam ações agendadas e atualizam seus amigos. Aqui está o código para
friendsReducer.js :
const INITIAL_STATE = { friends: [], friendsFetched: false }; function(state = INITIAL_STATE, action) { switch(action.type) { case 'FRIENDS_FETCHED': return { ...state, friends: action.payload, friendsFetched: true }; } }
▍4 Componente da lista de amigos
Este componente do contêiner exibe os dados dos amigos e atualiza a interface quando eles mudam. Além disso, ele é responsável por baixar os dados do repositório, se ele não os tiver. Aqui está o código para
friendsContainer.js :
class Container extends React.Component { constructor(props) { super(props); } componentDidMount() { if(!this.props.friendsFetched) { FriendsService.fetchFriends().then((data) => { this.props.onFriendsFetch(data); }); } } render() { const { friends } = this.props; return ( <View style={styles.flex}> <FriendsHeader count={friends.length} text='My friends' /> {friends.map((friend) => (<FriendRow {...friend} />)) } </View> ); } } const mapStateToProps = (state) => ({ ...state.friendsReducer }); const mapActionToProps = (dispatch) => ({ onFriendsFetch: (data) => { dispatch(FriendActions.onFriendsFetch(data)); } }); export default connect(mapStateToProps, mapActionToProps)(Container);
▍5. Componente de listagem de bate-papo
Esse componente de contêiner também usa dados do armazenamento e responde à sua atualização.
Sobre a implementação da arquitetura Redux
Pode levar um ou dois dias para trazer a arquitetura descrita acima para a condição de trabalho, mas quando alterações precisam ser feitas no projeto, elas são feitas de maneira muito simples e rápida. Se você precisar adicionar um novo componente ao aplicativo que usa dados sobre amigos, poderá fazer isso sem se preocupar com a sincronização de dados ou com a necessidade de refazer outros componentes. O mesmo vale para a remoção de componentes.
Teste
Ao usar o Redux, cada bloco de aplicativo pode ser testado independentemente.
Por exemplo, cada componente da interface do usuário pode ser facilmente submetido a testes de unidade, pois são independentes de dados. O ponto é que uma função que representa esse componente sempre retorna a mesma representação para os mesmos dados. Isso torna o aplicativo previsível e reduz a probabilidade de erros que ocorrem durante a visualização de dados.
Cada componente pode ser testado de forma abrangente usando uma variedade de dados. Esses testes revelam problemas ocultos e ajudam a garantir código de alta qualidade.
Note-se que não apenas os componentes responsáveis pela visualização dos dados, mas também redutores e criadores de ações podem ser submetidos a testes independentes.
O Redux é ótimo, mas, usando essa tecnologia, encontramos algumas dificuldades.
Dificuldades com o Redux
▍ Código de modelo em excesso
Para implementar a arquitetura Redux em um aplicativo, você precisa gastar muito tempo, enquanto encontra todo tipo de conceitos e entidades estranhos.
Estes são os chamados trenós (thunks), redutores (redutores), ações (ações), camadas de middleware (middlewares), essas são as funções
mapStateToProps
e
mapDispatchToProps
, além de muito mais. Leva tempo para aprender tudo isso e, para aprender a usá-lo corretamente, é necessária prática. Existem muitos arquivos no projeto e, por exemplo, uma pequena alteração no componente para visualização de dados pode tornar necessário fazer alterações em quatro arquivos.
O cofre Red Redux é único
No Redux, o armazém de dados é construído usando o padrão singleton, embora os componentes possam ter várias instâncias. Na maioria das vezes, isso não é um problema, mas em determinadas situações, essa abordagem do armazenamento de dados pode criar algumas dificuldades. Por exemplo, imagine que há duas instâncias de um componente. Quando os dados são alterados em qualquer uma dessas instâncias, essas alterações afetam outra instância. Em certos casos, esse comportamento pode não ser desejável; pode ser necessário que cada instância do componente use sua própria cópia dos dados.
Sumário
Lembre-se da nossa principal pergunta, que é se vale a pena o tempo e o esforço para implementar a arquitetura Redux. Nós, em resposta a esta pergunta, dizemos ao Redux "sim". Essa arquitetura ajuda a economizar tempo e esforço no desenvolvimento e desenvolvimento de aplicativos. O uso do Redux facilita para os programadores fazer alterações frequentes no aplicativo e facilita os testes. Obviamente, a arquitetura Redux fornece uma quantidade considerável de código padrão, mas ajuda a dividir o código em módulos convenientes para trabalhar. Cada um desses módulos pode ser testado independentemente dos outros, o que ajuda a identificar erros no estágio de desenvolvimento e permite garantir programas de alta qualidade.
Caros leitores! Você usa o Redux em seus projetos?
