redux-saga
é uma lib que visa fazer side effects(efeitos colaterais) (i.e. coisas assincronas como data fetching e coisas impuras como acessar o cache do browser) em aplicações React/Redux mais fácil e melhor.
O modelo mental é que uma saga é como uma thread separada em sua aplicação que é unicamente responsável por side effects. redux-saga
é um redux middleware, que significa que essa thread pode ser estartada, pausada e cancelada na aplicação principal com normais redux actions, ela tem acesso a todo o state(estado) da aplicação redux e pode também dispatch(dispachar) ações.
Saga usa uma feature(característica) do ES6 chamada Generators para fazer fazer fluxos assincronos fáceis de ler, escrever e testar. (Se você não está familirizada com elas Aqui tem alguns links introdutórios) Para fazê-los, fluxos assincronos veja como o padrão assincrono JavaScript code. (algo como async
/await
, mas generators tem coisas mais incríveis que nós precisamos)
Talvez você já tenha usado redux-thunk
para lidar com sua busca de dados. Contrários ao redux thunk, você não acaba em callback hell, você pode testar fácilmente seus fluxos assincronos e suas actions continuam puras.
$ npm install --save redux-saga
ou
$ yarn add redux-saga
Alternativamente, você pode usar o fornecido UMD build diretamente no <script>
tag de uma página HTML. Veja Esta sessão.
Supomos que temos uma UI para buscar alguns dados dos usuários de um servidor remoto quando um botão é clicado. ( Breve resumo, iremos mostrar apenas ações disparados no código)
class UserComponent extends React.Component {
...
onSomeButtonClicked() {
const { userId, dispatch } = this.props
dispatch({type: 'USER_FETCH_REQUESTED', payload: {userId}})
}
...
}
O Component dispara uma simples action Object na Store. Criaremos uma Saga que escuta todos os USER_FETCH_REQUESTED
actions e dispara uma chamada na API para buscar usuários.
import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'
import Api from '...'
// trabalho do Saga: irá disparar uma ação USER_FETCH_REQUESTED
function* fetchUser(action) {
try {
const user = yield call(Api.fetchUser, action.payload.userId);
yield put({type: "USER_FETCH_SUCCEEDED", user: user});
} catch (e) {
yield put({type: "USER_FETCH_FAILED", message: e.message});
}
}
/*
Estarta fetchUser em cada ação disparada `USER_FETCH_REQUESTED`.
Permite concorrentes buscar de usuários
*/
function* mySaga() {
yield takeEvery("USER_FETCH_REQUESTED", fetchUser);
}
/*
Alternativa você pode usar takeLatest.
Não permite buscar concorrentes de usuários. Se "USER_FETCH_REQUESTED" captura dispachados enquanto uma busca já está pendente, esta busca pendente é chamada e só a mais recente irá executar.
*/
function* mySaga() {
yield takeLatest("USER_FETCH_REQUESTED", fetchUser);
}
export default mySaga;
Para executar nosso Saga, teremos que conectar isto ao Redux Store usando o redux-saga
middleware
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducers'
import mySaga from './sagas'
// criação do saga middleware
const sagaMiddleware = createSagaMiddleware()
// agrupe na store
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
)
// então execute o saga
sagaMiddleware.run(mySaga)
// renderiza a aplicação
- Introdução
- Conceitos Básicos
- Conceitos Avançados
- Recipes
- Recursos Externos
- Soluções de Problemas
- Glossário
- Refência da API
Exibe também uma build umd do redux-saga
disponível no diretório dist/
. Ao usar a build do umd redux-saga
está disponível como ReduxSaga
no objeto window. Isso permite que você crie o middleware Saga sem usar a sintaxe ES6 import
, assim:
var sagaMiddleware = ReduxSaga.default()
A versão umd é útil caso você não utilize Webpack ou Browserify. Você pode acessá-la diretamente através do unpkg.
As seguintes builds estão disponíveis:
Importante! Se o browser que você está trabalhando não suporta os ES2015 generators, você deve fornecer um polyfill válido, como o fornecido pelo babel
. O polyfill deve ser importado antes do redux-saga:
import 'babel-polyfill'
// then
import sagaMiddleware from 'redux-saga'
$ git clone https://github.com/redux-saga/redux-saga.git
$ cd redux-saga
$ npm install
$ npm test
Abaixo há os exemplos portados (até agora) dos repositórios do Redux.
Há três exemplos de contadores.
Exemplo usando Javascript puro e build UMD. Todo o código está inline no arquivo index.html
.
Para executar o exemplo, basta abrir index.html
no seu browser.
Importante: seu browser deve suportar Generators. A última versão do Chrome/Firefox/Edge oferecem suporte.
Exemplo usando webpack
e a API de alto nível takeEvery
.
$ npm run counter
# test sample for the generator
$ npm run test-counter
Exemplo usando uma API de baixo nível para demonstrar cancelamento de tarefas.
$ npm run cancellable-counter
$ npm run shop
# test sample for the generator
$ npm run test-shop
$ npm run async
# test sample for the generators
$ npm run test-async
$ npm run real-world
# sorry, no tests yet
Redux-Saga com TypeScript requer DOM.Iterable
ou ES2015.Iterable
. Se o seu target
é ES6
, provavelmente você não precisa fazer nada, mas para ES5
você precisará adicionar isso você mesmo.
Verifique seu tsconfig.json
e a documentação oficial para compiler options.
Você pode achar o logo oficial do Redux-Saga com diferentes versões no diretório de logos.
Apoie-nos com uma doação mensal e ajude-nos a continuar nossas atividades. [Tornar-se um apoiador]
Torne-se um patrocinador e obtenha seu logotipo em nosso README no Github com um link para seu site. [Tornar-se um patrocinador]