Reputation: 1162
What is the best practice to organize my action types and state when I have a large app? One issue might be that I want to use the same name because it is a similar action and a similar state.
Just for the discussion: what if I wanted to update two titles, do I need to use a name convention like FIRST_TITLE and SECOND_TITLE for the action type and firstTitle and seccondTitle for the state?
I am open to better solutions too.
Upvotes: 1
Views: 1011
Reputation: 1036
You can use something like redux-auto. It generate actions and reducers from your file system.
We are using it in product for a large project and its has really helped bring down the complexity. It's nice that each transformation has its own file and this becomes your generated action name + async code co-located to the same file.
A summary:
It takes the ideas of reducer composition one step further. Where instead of having a file that represents your reducer and creating individual actions functions.
redux-auto's approaches to have folders with individual JS files representing each action/transformation on the state and dynamically exposing this as functions
example
└── store/
├──user/
│ └── index.js
│ └── changeName.js
└──posts/
└── index.js
└── delete.js
Now from anyway in your app you can write
import actions from 'redux-auto'
...
actions.user.changeName({name:"bob"})
store/user/changeName.js
export default function (user, payload) {
return Object.assign({},user,{ name : payload.name });
}
Thats is!
If you want to listen for redux actions in third-party reducers. You can use as loose quality check against the function.
action.type == actions.user.changeName // "USER/CHANGENAME"
For something more advanced you can even see if an action is owned by a specific reducer
// Returns true if it's an action specifically for user
if(action.type in actions.user)
You can read more on the project page
Upvotes: 0
Reputation: 7113
In a large app, I've organized my code into modules, each with their own reducer, actions etc. Each module exports the action types and action creators, I use those exlusively and never just pass a string as type. This prevents any naming conflicts between modules - in fact I try to keep the action names short.
modules/items/actionTypes.js:
export const name = "items";
export const UPDATE_TITLE = `${name}/UPDATE_TITLE`;
modules/items/actions.js
import * as actionTypes from "./actionTypes";
export const updateTitle = (title) => ({
type: actionTypes.UPDATE_TITLE,
payLoad: title,
});
modules/items/reducer.js
import * as actionTypes from "./actionTypes";
const initialState = { title: "" };
const reducer = (state = initialState, action) {
switch(action.type) {
case actionTypes.UPDATE_TITLE: {
return {
...state,
title: action.payload,
};
}
}
}
export default reducer;
modules/comments/actionTypes.js
export const name = "comments";
export const UPDATE_TITLE = `${name}/UPDATE_TITLE`;
modules/comments/actions.js
import * as actionTypes from "./actionTypes";
export const updateTitle = (title) => ({
type: actionTypes.UPDATE_TITLE,
payLoad: title,
});
modules/comments/reducer.js
import * as actionTypes from "./actionTypes";
import * as itemActionTypes from "../items/actionTypes";
const initialState = { title: "" };
const reducer = (state = initialState, action) {
switch(action.type) {
case actionTypes.UPDATE_TITLE: {
return {
...state,
title: action.payload,
};
}
case itemActionTypes.UPDATE_TITLE: {
// Do something with the updated item title
}
}
}
export default reducer;
rootReducer.js
import { combineReducers } from "redux";
import { default as itemsReducer } from "modules/items/reducer";
import { default as commentsReducer } from "modules/comments/reducer";
export default combineReducers({
items: itemsReducer,
comments: commentsReducer,
});
EDIT: added reducers to answer comment
Upvotes: 0