-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Accessing the store without @connect-ing? #108
Comments
What specifically is your use case? If you |
Basic example: I have a component for showing a 'Task':
But now let's say my tasks have an assigned user that I want to show. In my case, I have a 'userId' property on the task, but without access to the store I need this passed into the component as a prop. This gets more and more complex with nesting. For example, if this is used in a TaskList component, then the TaskList needs be updated to have access to both the Task and Users of my store so I can pass the required props. If my user belongs to a group, and I want to show that in TaskItem... well, you see how it goes! If I had access to the store, I could do a lookup in the TaskItem and not have to rely on my parent component to resolve the related data. Thanks |
@jamiewinder this might not work with you but consider possibly using selectors (consider faassen/reselect) You taskData will exist in your store normalized but when you connect your task list or whatever use selectors to compose the userData with the taskData into a denormalized unit for consumption by your TaskItem component. This lets your dumb components be truly dumb, they get exactly and only what they need and they don't have to know how to query your user data |
Thanks @gnoff - it looks like it might help, though if I have my dumb components |
reduxjs/redux#419 might be of interest to you |
well i was actually meaning that your TaskList or something higher might connect and it would receive the denormalized task data but you can really do it any way. The thing I think is important here is just that your TaskItem has an API (which includes user info) so it's preferable to satisfy that API externally via props than have to know about redux and query for user state within TaskItem. |
closing since I think this isn't actionable. tagged as question |
If you really really need class MyComponent {
someMethod() {
doSomethingWith(this.context.store);
}
}
MyComponent.contextTypes = {
store: React.PropTypes.object.isRequired
}; |
Hi, I'm struggling with the same issue, actually. It's entirely possible that in the long run, reading the store directly is the "wrong" way of going about things, but for now, it's what I need--or would like, at any rate. My problem is that My index.js file looks like this:
...and then within App.js'
... |
Context is opt-in; you have to specify |
Oh, also, if you want to access constructor(props, context) {
super(props, context);
console.log("context", this.context);
} You can skip this if you're only reading it later because React will put |
bless you. (-; |
Just a note about using In my case, using contextTypes on a container component that uses react-router as well I did the following (assumes use of lodash).
|
What do you mean by “parent components”? It will not overwrite However, if you use inheritance, yes, you need to be careful. That said React actively discourages using inheritance for component classes. Just don’t use it. |
Sorry for the mixup. In my particular case, trying to grant access to the redux "store" in a component using The main app.js looks more or less like this.
Is there a way to avoid replacing other components context? |
Please show the full code. It is impossible to say what exactly was wrong without seeing where and how you applied |
Ok, here is the code. I am just pasting the relevant parts (ommitted lots of import calls). Thanks for looking into this @gaearon app.js (look at the OrderContainer component)
order-container.jsx
Feel free to critique anything that you see wrong/unusual :) |
Why are you doing this? OrderContainer.contextTypes = _.extend(OrderContainer.contextTypes, {
store: PropTypes.object.isRequired
});
|
Thanks for the quick reply @gaearon. At the time I posted my comment I needed access to The code I posted has been refactored and I no longer need the access state within the component (I check if there are changes to be saved in the reducer. So you are right, I don't need access the store from context.
The weird thing is, I don't have access to the store in a "connected" component. Here is the context for the OrderContainer component. I refactored the code and it is now much cleaner. I use the state from the |
We don’t provide access to it on purpose because people will misuse The reason for the overwriting in your case is that you are literally overwriting them. When you use mixins and |
Thanks Dan for all the info provided. It helps to understand redux better. |
Hello, react-redux 6.0 removed the possibility to use the legacy context to access the store. How would we do it now? It's ok that we shouldn't be using it but when you have lots of tiny components that need to access the store but not to re-render based on it, connecting is overkill and slows down terribly. |
@cristianocca : you might want to read the discussions in #1126 . What is your use case? How and why are you trying to access the store separately? What kind of performance issues are you seeing? |
@markerikson : I have some components (such as buttons, modals, menus, pretty much anything clickable) that need to access some data from the store but do not need to be re-rendered every time the store changes, nor going through any of the overhead added by connect(). These components just need to know the values from the store when interacted with (such as clicking). Also, I know that perhaps these components should not rely on the store at all but instead receive the props from somewhere else, but that's another story. Not only this, updating to version 6 also broke components that would render outside of the main component. An example of this is the react material-ui Dialog component, which renders its content as a top level component. This change made it impossible to have connected components that render inside such Dialogs because they don't have access to the store at all now. I'm not criticizing the change, I actually like that you guys are keeping up with react's recommended implementation, but I wish this wouldn't be such of a breaking change and a migration / work around path was documented in the same changelog. |
@cristianocca : the migration should just have been updating the version of React-Redux you're using, with the couple exceptions that were documented in the release notes. If you're having further problems, please file a separate issue to discuss those. I'm particularly confused by your description of Material-UI dialogs. If you only need to access some data from the store when the action is being dispatched, I'd say that's a perfect use case for a thunk: function doSomethingWhenClicked(someId) {
return (dispatch, getState) => {
const state = store.getState();
const item = state.items[id];
dispatch({type : "SOMETHING_HAPPENED", payload : {item}});
}
} That way your component just calls |
@markerikson : I understood the exceptions, but I failed to find a way to keep the previous behavior with the new version (and hence my question here). You are right about using a thunk, but again, literally all I need in the componet is a simple value check from the store. Do I really need to go through all the overhead of making an action, connecting, and dispatching just to achieve something as simple as doing this.context.store.getState().someValue in a component check? The previous way of obtaining the state from the context was really good for these cases, and had no impact on performance. I'm talking about a component that's probably instantiated over a 100 times. About the Material-ui Dialog component issue (sorry if this goes offtopic). The 0.x version implementation simply creates a component for the modal under the react's root node, and hence it is not inside the redux node sub-tree, which means it won't have access to the store and any component rendered in it will fail to connect. This wasn't an issue with version < 6 and is likely related to the same context change. |
@cristianocca : the discussion in #1126 shows how to access the store state yourself if you really need it. That said, please note that is not considered part of the official API. Problems with MaterialUI should probably be filed on that repo. That said, if there's use cases the current React-Redux API doesn't cover, please file a separate issue with your concerns and use cases, and we can discuss things there. |
@cristianocca : we just added a docs page that shows the techniques discussed in #1126: https://react-redux.js.org/using-react-redux/accessing-store#using-reactreduxcontext-directly |
@markerikson : That's great, thanks! |
Is there currently a way for a component to access the root Provider store without being
connect
-ed to it? It sounds like it might be a bit of an anti-pattern, but I'm not sure. I've a couple of circumstances where I can see it coming in handy (dumb components which can still query related data from prop).The text was updated successfully, but these errors were encountered: