-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial React Native & Redux Persist
O vídeo referente a este tutorial está disponível em: link
Neste tutorial, serão abordados todos os passos para a criação de aplicativos híbridos utilizando o framework, do Facebook, React Native e como promover o gerenciamento e persistência local de estados desses aplicativos por meio do uso das bibliotecas redux, react-redux e redux-persist.
Com o projeto React Native já criado, usaremos o npm para instalar as bibliotecas necessárias para este tutorial, a partir da linha de comando:
npm install redux react-redux redux-persist @react-native-async-storage/async-storage
Redux (doc)
A biblioteca Javascript Redux ajuda o desenvolvedor no gerenciamento de estados dentro das aplicações. O gerenciamento acontece de forma centralizada no store, onde os estados são armazenados e modificados através de actions e reducers. O ambiente centralizado permite que os estados sejam compartilhados entre diferentes telas dentro da aplicação. Isso é bastante útil em aplicações de larga escala uma vez que permite à que equipe de desenvolvimento um completo conhecimento sobre o fluxo de dados, reduzindo potenciais bugs.
.
├── ...
├── src
│ ├── ...
│ ├── store
│ | ├── reducers
| | | ├── user
| | | | ├── actions.ts
| | | | └── reducer.ts
| | | └── rootReducer.ts
│ | └── index.ts
│ └── ...
└── ...
O state de uma aplicação corresponde a todas as informações que ela usa e/ou modifica.
Essas duas entidades, junstas, modificam o state. As actions determinam o que será modificado e onde. Reducers, por sua vez, especificam como o state é modificado. As actions são objetos com dois atributos: type e payload. O type é o indentificador de cada action e o payload é toda a informação necessária para modificar o state. Neste tutorial, teremos duas actions: SET_USER e CLEAR_USER. A primeira possui um payload especificando as informações sobre o usuário que devem ser atribuídas à propriedade user do nosso state. A última apenas especifica que o atributo user deve ser 'limpo', ou seja, deve retornar ao seu estado inicial e, por isso, apenas determinamos o atributo type no momento da criação do objeto.
// src/store/reducers/user/actions.ts
const SET_USER = 'SET_USER';
const CLEAR_USER = 'CLEAR_USER';
export const setUserAction = (user: { name: string, phone: string, email: string }) => ({
type: SET_USER,
payload: user
});
export const clearNameAction = () => ({
type: CLEAR_USER
});
// src/store/reducers/user/reducer.ts
const initialState = {
user: {
name: '',
phone: '',
email: ''
}
}
export default (state = initialState, action: any) => {
switch (action.type) {
case 'SET_USER':
return {
...state, user: action.payload
};
case 'CLEAR_USER':
return {
...state, ...initialState
};
default:
return state;
}
}
Uma boa prática em aplicações com muitos reducers, que usam o Redux, é utilizar a função combineReducers para unir todos os reducers do projeto em um único, que será usado na criação do store.
// src/store/reducers/rootReducer.ts
import { combineReducers } from 'redux';
import user from './user/reducer';
const rootReducer = combineReducers({
user
});
export default rootReducer;
O store é o objeto onde o state é armazenado. O store é criado a partir do método createStore() do Redux, que recebe como argumento o reducer criado.
// src/store/index.ts
import { createStore } from "redux"
import rootReducer from "./reducers/rootReducer"
export default createStore(rootReducer)
React Redux (doc)
Para que o store esteja disponível em todo o escopo da aplicação, ele é passado para o componente Provider, que importamos da biblioteca react-redux, que envolve nosso componente Routes. Dessa forma, o Provider pode prover acesso ao store nos componentes envoltos por ele e em todos dentro destes.
// App.tsx
import React from 'react';
import { Provider } from 'react-redux';
import { store } from './src/store';
export default function App() {
return (
<Provider store={store}>
<Routes/>
</Provider>
);
}
Nós utilizaremos as hooks disponibilizadas pela biblioteca react-redux para ter acesso às informações sobre os estados e realizar modificações nelas, através das actions.
Permite que extraiamos dados do state do nosso redux usando uma função seletora. Essa função é invocada sempre que o componente da função é renderizado e sempre que uma action é invocada, alterando o state da aplicação.
const user = useSelector((state: any) => state.user);
Para fazer uso desse hook, iremos invocá-lo e armazenar isso em uma constante dispatch.
const dispatch = useDispatch()
Para fazermos o "disptach" de actions, importamos, em nosso componente, as funções anteriormente criadas que retornam o objeto representante da action. Passamos a função, então, como argumento para dispatch.
import { setUserAction, clearUserAction } from '../../store/reducers/user/actions';
...
dispatch(setUserAction({
name: 'name',
email: 'email@user.com',
phone: '3333-4444'
}));
...
dispatch(clearUserAction());
Redux Persist (doc)
A biblioteca Redux persist salva localmente o store do Redux de forma persistente. Sempre que a aplicação abrir novamente ou for recarregada, o store é resgatado do armazenamento local.
Para fazer uso da biblioteca, devemos criar usar o método persistReducer que recebe como parâmetro um objeto com as configurações (chave e storage) e nos retorna um reducer. A partir do reducer retornado, podemos obter o objeto persistor a partir do método persistStore, que recebe como paraâmetro nosso store. O objeto é, então, exportado para usarmos no App.tsx.
// src/store/index.ts
import { createStore } from 'redux';
import rootReducer from './reducers/rootReducer';
import { persistStore, persistReducer} from 'redux-persist';
import AsyncStorage from '@react-native-community/async-storage';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(persistedReducer);
const persistor = persistStore(store);
export { store, persistor };
Envolvemos nossa aplicação com o componente PersistGate, que atrasa a renderização das interfaces da aplicação até que o state persistido tenha sido resgatado e salvo no Redux.
// App.tsx
import React from 'react';
import { Provider } from 'react-redux';
import { store } from './src/store';
import { PersistGate } from 'redux-persist/integration/react';
export default function App() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<Routes/>
</PersistGate>
</Provider>
);
}