owned this note
                
                
                     
                     owned this note
                
                
                     
                    
                
                
                     
                    
                
                
                     
                    
                        
                            
                            Published
                        
                        
                            
                                
                                Linked with GitHub
                            
                            
                                
                                
                            
                        
                     
                
            
            
                
                    
                    
                
                
                    
                
                
                
                    
                        
                    
                    
                    
                
                
                
                    
                
            
            
         
        
        ---
slideOptions:
  transition: fade
  controls: false
---
<!--
    Marcus: Intro, Controlling a Saga, Fazit
    Moritz: Generators, Testing
    Leo: Example + Demo, Advanced Use Cases
-->
<style>
img {
    border: none !important;
    width: 30vh;
    object-fit: contain;
    background: none !important;
    box-shadow: none !important;
}
p code:not(.hljs),
li code:not(.hljs) {
    color: #dc8c8c;
}
.reveal blockquote {
    padding: 0 25px;
}
.profilepics > div {
    display: flex;
    justify-content: space-around;
}
.profilepics img {
    border-radius: 50%;
    height: 25vh;
    width: 25vh;
    object-fit: cover;
    max-width: 100%;
}
.profilepics h2 {
    font-size: 3vh;
    margin-bottom: 0;
}
.profilepics h3 {
    font-size: 2vh;
}
.hljs {
    font-size: 80%;
}
</style>
# Redux Saga
#### Transparent Asynchronous State Changes
*React Meetup Düsseldorf*
---
<!-- .slide: class="profilepics" -->
<div class="image">
    <img src="https://i.imgur.com/m7xBGhd.jpg" width="300" height="300">
    <h2>Leo Bernard</h2>
    <h3>github.com/leolabs</h3>
</div>
<div class="image">
    <img src="https://i.imgur.com/WIwJk9U.jpg" width="300" height="300">
    <h2>Marcus Weiner</h2>
    <h3>github.com/mraerino</h3>
</div>
<div class="image">
    <img src="https://i.imgur.com/vE8DKi4.jpg" width="300" height="300">
    <h2>Moritz Gunz</h2>
    <h3>github.com/NeoLegends</h3>
</div>
---
### Nice to have
- ES2015
- Redux knowledge
- Test Assertions
Note:
Marcus
---
# 😅
## Finding a way to do async things with Redux
Note:
- Reducers are synchronous
- many async actions in a bigger webapp
---
### Cases
- Data fetching
- Data subscriptions
- Retry, Cancel, Debounce
- Rollbacks / Optimistic updates
- Integrating async actions into the redux state machine
---
# 🎉
## Saga
---
> [...] a Saga is like a separate thread in your application that's solely responsible for side effects.
---
# 👾
## Actor model
---
# ☸️
## What Can a Saga Do?
---
- Await events
- Interoperate with Redux
- Manage other sagas
---
# 🏭
## Generators
Note:
Moritz
- Wer kennt das?
---
```javascript
function* generator() { /* ... */ }
const iterator = generator() // => Object
```
```javascript
iterator.next() => { value: T | undefined, done: bool }
```
<!-- .element: class="fragment" -->
```javascript
for (const item of iterator) { // calls iterator.next()
  console.log(item)
}
```
<!-- .element: class="fragment" -->
Note:
- Generator returns iterator
  - Object to traverse a collection
- works with for...of
- function only runs on call to .next()
---
```javascript
function* generator() {
  const num = 2
  // Pass value to callee and pause execution
  yield 1
  
  
  
  
  
  
}
```
```javascript
const iterator = generator()
```
Note:
- Yield -> resumable function with context
- Try-catch / if-else, etc.
- Push values into generator
---
```javascript
function* generator() {
  const num = 2
  // Pass value to callee and pause execution
  yield 1
  
  
  
  
  
  
}
```
```javascript
const iterator = generator()
// Generator progress controlled from outside
iterator.next().value   == 1
```
Note:
- Yield -> resumable function with context
- Try-catch / if-else, etc.
- Push values into generator
---
```javascript
function* generator() {
  const num = 2
  // Pass value to callee and pause execution
  yield 1
  // Callee can pass values into generator
  let a = yield 2
  
  
  
}
```
```javascript
const iterator = generator()
// Generator progress controlled from outside
iterator.next().value   == 1
iterator.next().value   == 2
```
Note:
- Yield -> resumable function with context
- Try-catch / if-else, etc.
- Push values into generator
---
```javascript
function* generator() {
  const num = 2
  // Pass value to callee and pause execution
  yield 1
  // Callee can pass values into generator
  let a = yield 2
  // `num` maintains value across yield points
  yield a + num
}
```
```javascript
const iterator = generator()
// Generator progress controlled from outside
iterator.next().value   == 1
iterator.next().value   == 2
iterator.next(10).value == 12
```
Note:
- Yield -> resumable function with context
- Try-catch / if-else, etc.
- Push values into generator
---
```javascript
function* generator() {
  const num = 2
  // Pass value to callee and pause execution
  yield 1
  // Callee can pass values into generator
  let a = yield 2
  // `num` maintains value across yield points
  yield a + num
}
```
```javascript
const iterator = generator()
// Generator progress controlled from outside
iterator.next().value   == 1
iterator.next().value   == 2
iterator.next(10).value == 12
iterator.next().done    == true
```
Note:
- Yield -> resumable function with context
- Try-catch / if-else, etc.
- Push values into generator
---
# ✨
## Effects
Note:
Leo
- "Glue" between generators and saga library
  - Way to control sagas
---
```javascript
function* saga() {
  yield put({
    type: "SET_JOKE",
    payload: "What do you call a fake noodle? An impasta!",
  })
}
```
```javascript
saga().next() == {
  PUT: {
    action: {
      type: "SET_JOKE",
      payload: "What do you call a fake noodle? An impasta!",
    }
  }
}
```
<!-- .element: class="fragment" -->
Note:
- Functions don't do anything themselves
- Return an object containing instructions for saga
- Saga receives instructions and acts on them
---
# 💻
## Example
---
```javascript
function* fetchJoke() {
  const { joke } = yield call(
    fetchJson,
    "https://icanhazdadjoke.com/",
  )
  yield put({ type: 'SET_JOKE', payload: joke })
}
```
```javascript
function* jokeThread() {
  while (true) {
    const action = yield take('GET_JOKE')
    yield fork(fetchJoke)
  }
}
```
<!-- .element: class="fragment" -->
Note:
- Why infinite loop?
    - Alright, because function is non-blocking
---
## DEMO
https://codesandbox.io/s/1q5856pww4
---
# 😍
## Why is Saga so great?
Note:
Marcus
---
### Model the Whole Story of Your App
**App Lifecycle**
Login → Interaction → Logout → Login ...
```javascript
function* app() {
  while (true) {
    yield waitForlogin()
    const pid = yield fork(runDataFetching)
    yield waitForLogout()
    yield cancel(pid)
  }
}
```
<!-- .element: class="fragment" -->
---
# ✅
## Testing our Saga
Note:
Moritz
---
```javascript
it("should fetch a joke and store it in the state", () => {
  const jokeMock = {
    joke: "Chuck Norris knows the last digit of pi."
  }
  const it = fetchJoke()
})
```
---
```javascript
it("should fetch a joke and store it in the state", () => {
  const jokeMock = {
    joke: "Chuck Norris knows the last digit of pi."
  }
  const it = fetchJoke()
  it.next() // returns { CALL: { ... } } effect object
  
  
  
  
  
  
  
})
```
---
```javascript
it("should fetch a joke and store it in the state", () => {
  const jokeMock = {
    joke: "Chuck Norris knows the last digit of pi."
  }
  const it = fetchJoke()
  it.next() // returns { CALL: { ... } } effect object
  expect(it.next(jokeMock).value).toEqual(put({ 
    type: "SET_JOKE", 
    payload: jokeMock.joke,
  }))
  
  
})
```
---
```javascript
it("should fetch a joke and store it in the state", () => {
  const jokeMock = {
    joke: "Chuck Norris knows the last digit of pi."
  }
  const it = fetchJoke()
  it.next() // returns { CALL: { ... } } effect object
  expect(it.next(jokeMock).value).toEqual(put({ 
    type: "SET_JOKE", 
    payload: jokeMock.joke,
  }))
  expect(it.next())
    .toEqual({ done: true, value: undefined })
})
```
---
# 💡
## Advanced use cases
Note:
Leo
---
#### Debounce
```javascript
function* handleInput({ payload }) {
  yield delay(500)
  const res = yield call(
    fetch,
    "https://myAPI",
    { body: payload },
  )
}
function* watchInput() {
  yield takeLatest('INPUT_CHANGED', handleInput)
}
```
Note:
- Great for input fields that trigger searches
- Limit the amount of requests
---
#### Retries
```javascript
function* request() {
  while (true) {
    const res = yield call(fetch, "https://myAPI")
    
    if (res) {
      put(...)
      return
    }
    
    yield delay(5000)
  }
}
```
Note:
- Good for flaky connections
---
# 🏁
## Conclusion
---
- Actor Model for the Frontend<!-- .element: class="fragment" -->
- Declarative 😍<!-- .element: class="fragment" -->
- Sagas are pure (Runtime)<!-- .element: class="fragment" -->
- Enables sequential running of effects<!-- .element: class="fragment" -->
- Easy error handling<!-- .element: class="fragment" -->
---

## [github.com/Festify/app](https://github.com/Festify/app)
Note:
Leo
---
# ❤️
## Thank you!
---
## Saga "Without" Redux
```javascript
const io = {
  dispatch(action) => /* saga dispatches an action */,
  getState() => /* saga requests app state */,
  subscribe(callback) =>  /* on action: callback(action) */,
}
runSaga(io, saga)
```