toddmotto / angularjs-styleguide

AngularJS styleguide for teams
https://ultimateangular.com
5.96k stars 700 forks source link

[RFC] clarification of redux's usage #114

Closed iamdey closed 8 years ago

iamdey commented 8 years ago

It could be great to have something for structuring a redux based angular app:

Actions

can be easily defined using service declaration in module component

// file:app/component/todo/todo.actions.js
export const ADD_TODO = 'ADD_TODO';

class TodoActions {
  constructor($http) {
    this.$http = $http;
  }

  addTodo(todo) {
    return dispatch => this.$http.post('http://whatever/todos', { todo })
      .then((response) => dispatch({ 
        type: ADD_TODO,
        payload: response.data.todo,
      }));
  }
}

export default TodoActions;

// file:app/component/todo/index.js
import TodoActions from './todo.actions.js';

const todo = angular.module('todo', [])
  .service('TodoActions',  TodoActions)
  .name;

Reducers

Reducers are pure functions and must be stored in the component as well

// file:app/component/todo/todo.reducer.js
import { ADD_TODO } from './todo.actions.js';

function todoReducer(state = { todoById: { }, todos: [] }, action = {}) {
  switch(action.type) {
    case ADD_TODO:
      return { 
        ...state,  
        todoById: { ...state.todoById, [action.payload.todo.id]: action.payload.todo },
        todos: [...state.todos, action.payload.todo.id],
     };
    default:
      return state;
  }
}

export default todoReducer;

They both need todoReducer and they have same importance, one cannot be a common module component.

Middlewares

can be declared as factory in both module component and app component depending of the scope of the side effect.

// file:app/component/todo/todo.middleware.js

import { ADD_TODO } from './todo.actions.js';

function todoMiddleware(todoLogger) {
  return store => next => action => {
    if (action.type === ADD_TODO) {
      todoLogger('lolilol', store.getState(), action.payload);
    }

    return next(action);
  };
}

export default todoMiddleware;

// file:app/component/todo/index.js
import todoMiddleware from './todo.middleware.js';

const todo = angular.module('todo', [])
  .factory('todoMiddleware',  todoMiddleware)
  .name;
file:app.config.redux.js;
import todoReducer from 'app/component/todo/todo.reducer.js';

const reducers = combineReducers({
  todoReducer,
});

import reducer from ...;
function ReduxConfig($ngReduxProvider) {
  $ngReduxProvider.createStoreWith(reducers, [
    'todoMiddleware',
  ]);
}
export default ReduxConfig;

Further

Here I used ngRedux, I didn't know about ng-component-redux, I'll take a look asap, hope it helps to pass props to reselect functions.

I've started to migrate the app I'm working on to this styleguide, I still have doubts and I'm using redux and reselect since a while. It is a free (libre) software, for curious people the source code is here: https://github.com/CaliOpen/caliopen.web-client-ng/tree/chore/angularjs_styleguide_es2015

floriangosse commented 8 years ago

Thank you for sharing your structure. I'm actually thinking about moving the data structure of an existing application to redux and had similar approaches in mind.

I would be nice to have a section with a example of Angular and Redux.

toddmotto commented 8 years ago

@floriangosse Do you have any articles that we can link to that promote this practice well? I'd be interested in writing up a blog post on 1.5 and $ngRedux so until then it may be worth dropping a "resource" in.