I'm refactoring some Flux stores/actions/action creators to be more Fluxy (PUBLISH
, PUBLISH_SUCCESS
, PUBLISH_FAILURE
instead of a weird IS_LOADING
action), and was wondering how to structure my actions: should my action creators call single actions (PUBLISH_SUCCESS
) or multiple ones (ADD_AUTHOR
, ADD_BOOK
, etc)?
Here's a more specific example:
I have a TasksStore
that holds todo items for my innovative new task-management app, and I have a poorly named action creator TaskActions
that lets me fetch my varieties from the server and add new ones with an API. Kinda like this:
const TasksStore = { ... };
const TaskActions = {
fetchTasks(),
addTask()
};
What actions should I dispatch to communicate with TasksStore?
I see two options: action-creator-api-specific actions (FETCH_TASKS
, FETCH_TASKS_SUCCESS
, FETCH_TASKS_FAILURE
, ADD_TASK
, ADD_TASK_SUCCESS
, & ADD_TASK_FAILURE
) or reusable actions (ADD_TASK
called over and over for fetch and called once for addTask()
).
Basically, should my API look like this (verbose, perhaps redundant, dispatch-able actions for each action-creator-action):
const TasksStore = {
on('FETCH_SUCCESS', (tasks) => { // add tasks });
on('ADD_SUCCESS', (task) => { // add task });
};
const TaskActions = {
fetchTasks() {
dispatch('FETCH');
myApi.fetchTasks(
(success_payload) => { dispatch('FETCH_SUCCESS', success_payload) },
(failure_payload) => { dispatch('FETCH_FAILURE', failure_payload) }
);
},
addTask() {
dispatch('ADD');
myApi.addTask(
(success_payload) => { dispatch('ADD_SUCCESS', success_payload) },
(failure_payload) => { dispatch('ADD_FAILURE', failure_payload) }
);
}
};
or like this (concise, reusable dispatch-able actions):
const TasksStore = {
on('ADD', (task) => { // add task });
};
const TaskActions = {
fetchTasks() {
dispatch('FETCH');
myApi.fetchTasks(
(success_payload) => {
success_payload.forEach((task) => { dispatch('ADD', task); })
},
(failure_payload) => { dispatch('FETCH_FAILURE', failure_payload)
);
},
addTask() {
dispatch('ADD');
myApi.addTask(
(success_payload) => { dispatch('ADD', success_payload),
(failure_payload) => { dispatch('ADD_FAILURE', failure_payload)
);
}
};
or something in between?
Thanks!
We decided to go with the more verbose route:
For AJAX actions (like in the examples), we dispatch a specific "started" action, then a "success" or "failure" action:
dispatch('RETICULATE_SPLINES');
app.reticulateSpinesAndReturnPromise().then(
(success) => { dispatch('RETICULATE_SPLINES_SUCCESS'); },
(failure) => { dispatch('RETICULATE_SPLINES_FAILURE'); }
);
Why?
ActionCreator.fetchMessages
will dispatch a FETCH_MESSAGES
action, not ADD
or FETCH_OR_ADD
or something weird. It's a lot easier to understand a decoupled system like actions and stores (decoupled because all actions travel through a dispatcher) when there are no unexpected dispatches.MessageThreadsStore
need to update when we .fetchMessages()
but not .postMessage()
? Listen for FETCH_MESSAGES_SUCCESS
, not ADD
which might have been called in both otherwise.Anyway, hope that helps.