An open API service indexing awesome lists of open source software.

https://github.com/yornaath/use-saga-reducer

Use redux-saga with react reducer hook, with convenience methods for running sagas from components.
https://github.com/yornaath/use-saga-reducer

hooks react react-hooks redux-saga saga state-management

Last synced: 3 months ago
JSON representation

Use redux-saga with react reducer hook, with convenience methods for running sagas from components.

Awesome Lists containing this project

README

          

# use-saga-reducer

Use redux-saga with react reducer hook, with convenience methods for running sagas from components.

```typescript
import React, { useEffect, useState, useRef } from 'react'
import { useSaga } from '../../../src'
import { takeEvery, select, delay, put } from 'redux-saga/effects'

const reducer = (count: number, action: any) => {
switch(action.type) {
case 'INCREMENT':
return count + 1
case 'DECREMENT':
return count - 1
case 'RESET_COUNT':
return 0
}
return count
}

const resetAt = (max: number) => function*() {
yield takeEvery('INCREMENT', function*() {
const count = (yield select()) as number
if(count >= max) {
yield put({type: 'RESET_COUNT'})
}
})
}

export const Counter = (props: {max: number}) => {

const [count, dispatch, useRun] = useSaga(reducer, 0, resetAt(props.max))
const [cycle, setCycle] = useState(0)

useRun(function* () {
yield takeEvery('RESET_COUNT', function*(a) {
setCycle( cycle +1 )
})
}, [cycle])

return (

dispatch({type: 'INCREMENT'})}>+
dispatch({type: 'DECREMENT'})}>-

counter: {count}

cycle: {cycle}


)
}
```

### Example with typed store

#### SimpleComponent.tsx
```typescript
import React from 'react'
import { reducer, saga, ping, State, ActionEvent } from './store'
import { useSaga } from '../../../src'
import { take, select } from 'redux-saga/effects'

const initialState: State = {
events: []
}

const takePings = (until: number) => function* () {
while(yield take('ping')) {
const events = (yield select((s) => s.events)) as ActionEvent[]
const nrOfPings = events.filter(e => e === 'ping').length

if(nrOfPings === until)
return "counting done"
}
}

export default () => {

const [state, dispatch, useRun] = useSaga(
reducer,
initialState,
saga
)

const counted = useRun(takePings(4), [])

return (
<>


dispatch(ping())}>Ping


{state.events.map((event, index) => (

{event} {' '}

))}

{
state.error &&
{ state.error }
}



{
counted.loading ?
counting.. :
counted.value ?
{ counted.value } :
""
}

>
)
}
```

#### GlobalSagaReducer.tsx
```typescript
import React from 'react'
import { useSaga } from 'use-saga-reducer'
import { reducer, saga, ping, State } from './store'

const initialState: State = {
events: []
}

const sagaContext = createSagaContext(reducer, initialState, saga)

export default () => {
return (




)
}

export const Inner = () => {

const [state, dispatch, useRun] = sagaContext.use()

return (
<>


dispatch(ping())}>Ping


{state.events.map((event, index) => (

{event} {' '}

))}

{
state.error &&
{ state.error }
}

>
)
}
```

#### store.ts
```typescript

import { take, put, delay, select, SelectEffect } from 'redux-saga/effects'

export type Ping = 'ping'
export type Pong = 'pong'

export type PingActionType = {
type: Ping
}

export const ping = (): PingActionType => ({
type: 'ping'
})

export type PongActionType = {
type: Pong
}

export const pong = (): PongActionType => ({
type: 'pong'
})

export type ActionType =
PingActionType
| PongActionType

export type ActionEvent =
Ping
| Pong

export type State = {
events: ActionEvent[]
error?: string
}

export const reducer = (state: State, action: ActionType): State => {
switch(action.type) {

case 'ping':
const isWaitingForPong = state.events[state.events.length - 1] === 'ping'

if(isWaitingForPong)
return { ...state, error: 'Invariant: trying to ping while ponging!'}

return {
events: [...state.events, 'ping']
}

case 'pong':
const isWaitingForPing = state.events[state.events.length - 1] === 'pong'

if(isWaitingForPing)
return { ...state, error: 'Invariant: trying to pong while pinging!'}

return {
events: [...state.events, 'pong']
}

}
}

export const saga = function* saga() {
while(yield take('ping')) {
yield delay(800)
yield put(pong())
}
}
```