Comments (8)
I'll write up an RFC for this addition and see what everyone thinks.
from redux-logic.
I have added logicMiddleware.addDeps(additionalDeps)
which will allow you to add dependencies after createStore has been called (similar to the example I provided). It is now available as of v0.11.7
https://github.com/jeffbski/redux-logic/releases/tag/v0.11.7
I'll go ahead and close this, but if there are any additional questions just let me know.
from redux-logic.
We've been using this approach for setting API credentials:
When a token is fetched from somewhere, it is stored in state by sending save-api-token
action (ends up saved in some reducer). Then there's also a logic that listens for this save-api-token
action and gets api
dependency and calls api.setAuthToken(action.payload.token)
on it as a side-effect (api
instance now saves it internally as this._token
). Now every other logic just needs to use api
dependency and call any api.doSomethingResty
calls without having to know about tokens at all.
from redux-logic.
@michael-wolfenden thanks for the kind feedback and for submitting this issue.
I believe I understand what you need here. I want to be careful to allow people to use deps to pass in any sort of object, function, or primitive, so we'd have to keep that in mind with any additions. To go down that path, it seems like we'd need a special way to signify that this is a fn that receives state if redux-logic is supposed to automatically provide it and thus the API becomes a little more complex.
So I'm assuming that you would have something like this currently.
const api = {
foo(accessToken, id) // returns a promise
}
const logicMiddleware = createLogicMiddleware(logic, { api });
const fooLogic = createLogic({
type: FOO,
process({ getState, action, api }, dispatch, done) {
const accessToken = getState().accessToken;
const id = action.payload;
api.foo(accessToken, id)
.then(result => dispatch({ type: FOO_SUCCESS, payload: result }))
.then(() => done());
}
});
Personally this is how I like to craft my logic so that all of the redux related stuff is encapsulated in the logic keeping my API clean and separate from anything redux, so it can be used in other ways even without redux. So for me all the mapping to and from actions, state, selectors, dispatching, all of that occurs inside the logic so that everything else can stay pure. It is also a good practice to use selectors to find things in the state so you can easily restructure the state as necessary, so in the above example
const accessToken = accessTokenSelector(getState()); // in fooLogic
// and the selector would have been defined in the same file with the reducer something like
export const accessTokenSelector = state => state.accessToken;
So for me this is ideal having the api.foo be passed in accessToken and id, the two things it needs to do its work. It is easy to test in isolation, I don't have to set up a full state when I only need the accessToken.
However in thinking through your desire to not need to always pass this accessToken through for every call. I'm guessing that your desired code would look like this.
const fooLogic = createLogic({
type: FOO,
process({ getState, action, api }, dispatch, done) {
const id = action.payload;
api.foo(id) // only need to pass in id, since foo already has getState
.then(result => dispatch({ type: FOO_SUCCESS, payload: result }))
.then(() => done());
}
});
Basically eliminating the need to retrieve and pass the accessToken inside the logic. So while I would still prefer the previous form, I can see how some might prefer less repetition (though we have basically shifted the selector call from the logic to inside the api call).
I had been already pondering the ability to add dependencies at runtime but I wanted to be careful on how this is done.
So I am wondering if that mechanism could be used to help you with your goal as well.
Here's how your code might look if we added the addDeps
method to redux-logic.
function createAPI(getState) {
// we basically capture getState in our closure so it doesn't have
// to be passed in later
return { // api
foo(id) {
const accessToken = accessTokenSelector(getState());
// return promise
}
}
}
const logicMiddleware = createLogicMiddleware(logic);
const store = createStore(reducer, applyMiddleware(logicMiddleware));
logicMiddleware.addDeps({
api: createAPI(store.getState)
});
const fooLogic = createLogic({
type: FOO,
process({ getState, action, api }, dispatch, done) {
const id = action.payload;
api.foo(id)
.then(result => dispatch({ type: FOO_SUCCESS, payload: result }))
.then(() => done());
}
});
If we added something like addDeps
does that move your code in the desired direction?
from redux-logic.
Thank @jeffbski for your response
Your correct in regards to how we are currently using it. We are also using a selector to access the token.
In terms of addDeps
rather than closing over store.getState
, I was thinking more in terms of
const deps = {
api: (state) => createAPI(state)
};
const logicMiddleware = createLogicMiddleware(arrLogic, deps);
So the api
passed into proccess
is the result of executing this function with the current state.
Having said that either way will solve my issue.
from redux-logic.
Yeah, I thought that's what you were getting at. My main reason for suggesting the alternative is that otherwise we'd need a way to indicate that a dependency needed to be called with state first before providing to the hooks. We can't just take the fact that it is a function since we could have lots of other deps that are functions (which are not expecting to be called prior to injection). So we'd likely have to use a special key or wrap in an object deps that need pre-execution with state. It gets even worse if we provide state rather than getState since then we have to execute this for each an every one of these before each and every hook in each and every logic even if they don't use them.
Thus we will bypass a bunch of API complexity and extra work if we go with the addDeps approach.
What should we call these injected dependencies? Is deps
clear enough? or is something like locals
better? Originally I would have used context
, but since React has context and we also have a pre-created variable name ctx (for sharing between hooks), so I went with the term deps.
Since I'm adding a new API method, I guess I better see if this is the best term. We can always change variable names around later, but API method names are more rigid.
Any thoughts on the best term for these injected dependencies?
from redux-logic.
Hmmm, I see what you mean.
How about stateDeps
instead of deps
?
from redux-logic.
@tehnomaag That sounds like a nice approach, thanks for sharing.
from redux-logic.
Related Issues (20)
- hook for optimistic ui updates
- failType not triggered for rejected promise HOT 3
- Error in StandardAction generic type definition ? HOT 7
- Type error when specifying payload type HOT 2
- Why is CreateLogic.Config.Transform.Hook uses optional argument for reject? HOT 2
- How to delay a dispatch HOT 2
- done cb in finally does not trigger dispatch HOT 2
- Can not make 'latest' property work HOT 2
- processReturn plus processMultiple
- Feature request: `logicMiddleWare.removeLogic(logics)` HOT 2
- can't test Timers and/or cancelType HOT 1
- Is this repo archived, can't see any active development HOT 2
- Type Error while trying to dispatch an Observable
- Improve bundle size by dropping RxJS and improving build process?
- example of post using ajax HOT 4
- `NODE_ENV` is always '' (empty string) in browser. HOT 1
- createLogic type can be string array
- Websockets redux-logic and SSR
- redux-logic v4.0.0 is not in npmjs.com HOT 1
- action (with type) in `catchError` returned observable is not dispatched HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from redux-logic.