title: Managing state in angular2 application - side effects?
body: <p>This is more of a general question, but based on Victor Savkin  post <a href="http://victorsavkin.com/post/137821436516/managing-state-in-angular-2-applications" rel="nofollow"> Managing state in angular2</a></p>
  
  <p>Let's consider approach described there that uses RxJs:</p>
  
  <pre><code>interface Todo { id: number; text: string; completed: boolean; }
  interface AppState { todos: Todo[]; visibilityFilter: string; }
  
  function todos(initState: Todo[], actions: Observable&lt;Action&gt;): Observable&lt;Todo[]&gt; {
    return actions.scan((state, action) =&gt; {
      if (action instanceof AddTodoAction) {
        const newTodo = {id: action.todoId, text: action.text, completed: false};
        return [...state, newTodo];
      } else {
        return state;
      }
    }, initState);
  }
  </code></pre>
  
  <p>All is fine, but let's add few more requirements:</p>
  
  <ul>
  <li>Upon adding new Todo item, its text should be sent to the backend and analysed to extract possible due date and location.</li>
  <li>If Todo item has due date, it should be added to my Google calendar</li>
  </ul>
  
  <p>So if i add Todo "Get my hair done at Sally's Saloon on Thursday", with first call i would get from backend Sally's Saloon and date which is set to this weeks (or next weeks) Thursday and second call would add this todo to my Google calendar and mark item as in calendar.</p>
  
  <p>So my new Todo item structure might look something like this:</p>
  
  <pre><code>interface Todo { 
    id: number; 
    text: string; 
    completed: boolean; 
    location?: Coordinates; 
    date?: Date; 
    inCalendar?: boolean; 
    parsed?: boolean;
  }
  </code></pre>
  
  <p>And now i have two side effects :</p>
  
  <ol>
  <li>After todo has been added i need to parse the text</li>
  <li>After date has been added to Todo, i need to add it to calendar.</li>
  </ol>
  
  <p>How do i deal with these side effects in this approach? Redux says that reducers should be kept clean, and they also have a notion of Sagas.</p>
  
  <p><strong>Option 1 - fire new event(s) for side effects when todo is added</strong></p>
  
  <pre><code>function todos(initState: Todo[], actions: Observable&lt;Action&gt;): Observable&lt;Todo[]&gt; {
    return actions.scan((state, action) =&gt; {
      if (action instanceof AddTodoAction) {
        const newTodo = {id: action.todoId, text: action.text, completed: false};
        actions.onNext(new ParseTodoAction(action.todoId));
        return [...state, newTodo];
      } else if (action instanceOf ParseTodoAction){
        const todo = state.find(t =&gt; t.todoId === action.todoId)
        parserService
        .parse(todo.todoId, todo.text)
        .subscribe(r =&gt; actions.onNext(new TodoParsedAction(todo.todoId, r.coordinates, r.date)))
      } else {
        return state;
      }
    }, initState);
  }
  </code></pre>
  
  <p>But this will fail, because new todo is not yet available on the state. 
  I could of course use only <code>TodoParsedAction</code> and instead of <code>ParseTodoAction</code> just invoke backend call inline, but this would also assume that backend call will take longer to process, and by the time it finishes state will already have that new Todo item which is trouble waiting to happen.</p>
  
  <p><strong>Option 2 - subscribe to actions and check each todo for missing properties</strong></p>
  
  <pre><code>actions
  .flatMap(todos =&gt; Observable.from(todos))
  .subscribe(todo =&gt; {
    if (!todo.coordinates &amp;&amp; !todo.parsed) {
       parserService
        .parse(todo.todoId, todo.text)
        .subscribe(r =&gt; actions.onNext(new TodoParsedAction(todo.todoId, r.coordinates, r.date)))
    }
    if (todo.date &amp;&amp; todo.inCalendar === undefined) {
      calendarService
        .add(todo.text, todo.date)
        .subscribe(_ =&gt; actions.onNext(new TodoInCalendarAction(todo.todoId, true)))
    }
  })
  </code></pre>
  
  <p>But this somehow does not feel right - shouldn't be everything managed by actions, and should i always loop through all of todo items?</p>