-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Necessary to include request in middleware? #29
Comments
No! Ok, so I fumbled around with this for a while. Here is what came up with in case anyone else happens upon this. I completely skip the middleware. After all, Thunks, Sagas etc are just processed in middleware anyways (so REALLY I just happen to be Thunk as my middleware piece and get clever in my action) I happen to be using Thunk's to do this, but any asyncronous dispatching should be fine let nextTransactionID = 0;
async function thunkAction(): ThunkAction<Promise<void>, IReduxState, undefined> {
const transactionID = nextTransactionID++;
try {
// Optimistic dispatch
dispatch({ ...newDataActionCreator(optimisticData),
meta: { optimistic: { type: BEGIN, id: transactionID } },
});
const response = await fetch(...);
const realData = await response.json().data;
// Ok, now lets rewrite with our real data
// note that the state after optimistic dispatch is the starting point for this dispatch
// Either have a different action here, or ensure that applying the action with the real data AFTER
// the action with the optimistic data gives you your desired state
dispatch({ ...newDataActionCreator(realData),
meta: { optimistic: { type: COMMIT, id: transactionID } },
});
} catch(err) {
// Here, the state is reverted to before the optimistic dispatch before applying the next dispatch
dispatch({ ...errorActionCreator(new Error('Fetch failed')),
meta: { optimistic: { type: REVERT, id: transactionID } },
});
} |
I know this is an old issue, but I will show another example for good measure. //ReduxOptimisticMiddleware.js
import { BEGIN, COMMIT, REVERT } from "redux-optimistic-ui";
//All redux action types that are optimistic have the following suffixes
const _SUCCESS = "_SUCCESS";
const _ERROR = "_ERROR";
//Each optimistic item will need a transaction Id to internally match the BEGIN to the COMMIT/REVERT
let nextTransactionID = 0;
export default store => next => action => {
// FSA compliant
const { type, meta, error, payload } = action;
// Ignore actions without isOptimistic flag
if (!meta || !meta.isOptimistic) return next(action);
const isSuccessAction = type.endsWith(_SUCCESS);
const isErrorAction = type.endsWith(_ERROR);
//Response from server, handled in epic-middleware
if (isSuccessAction || isErrorAction) {
return next(action);
}
// Now that we know we're optimistically updating the item, give it an ID
let transactionID = nextTransactionID++;
// Sending to server; extend the action.meta to let it know we're beginning an optimistic update
return next(
Object.assign({}, action, {
meta: { optimistic: { type: BEGIN, id: transactionID } }
})
);
}; //epics.js
const editApp = action$ =>
action$.ofType(actions.APP_EDIT).concatMap(action => {
const { app, data } = action.payload;
return api
.updateApp(app.id, data)
.then(resp =>
actionCreators.commitOrRevertOptimisticAction(
actionCreators.editAppSuccess(app, data),
action
)
)
.catch(error =>
actionCreators.commitOrRevertOptimisticAction(
actionCreators.actionErrorCreator(
actions.APP_EDIT_ERROR,
error
),
action
)
);
});
export default combineEpics(editApp); //actionCreators.js
const optimisticActionCreator = action => ({
...action,
meta: { ...action.meta, isOptimistic: true }
});
export const commitOrRevertOptimisticAction = (
action,
transaction,
error = false
) => {
if (action.error) {
error = true;
}
let transactionID = transaction;
if(transaction && transaction.meta && transaction.meta.optimistic) {
transactionID = transaction.meta.optimistic.id;
}
return {
...action,
meta: {
...action.meta,
optimistic: error
? { type: REVERT, id: transactionID }
: { type: COMMIT, id: transactionID }
}
};
};
//This is what my actionCreators will look like
export const optimisticEditApp = (app, data) =>
optimisticActionCreator(
actionCreator(actions.APP_EDIT)({
app,
data
})
); That's it! All I do to have an action being optimistic is decorating it with optimisticActionCreator. In my views I can just do |
I have all of my requests set up to fire within my Sagas. I noticed in your example you use
socket.emit
and then the response to create a Redux action.Is it necessary to have the
socket.emit
request in the middleware for redux-optimistic-ui to work? If it isn’t necessary, are there any examples that illustrate that?The text was updated successfully, but these errors were encountered: