Skip to content
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

Access store from context? #1123

Closed
badtant opened this issue Dec 13, 2018 · 14 comments

Comments

@badtant
Copy link

commented Dec 13, 2018

Hi, I just updated to 6.0.0 and have a question. I can't really figure out from the docs how to access the store from context anymore.

My app is wrapped with
<Provider store={store}>

Then in any component I could access it with

MyComponent.contextTypes = {
    store: PropTypes.object.isRequired
};

->

this.context.store

How do i achieve the same thing with 6.0.0?

@timdorr

This comment has been minimized.

Copy link
Member

commented Dec 13, 2018

We use the new context API, which is exported as ReactReduxContext.

@timdorr timdorr closed this Dec 13, 2018

@badtant

This comment has been minimized.

Copy link
Author

commented Dec 17, 2018

Got it working but this also seem to subscribe to updates from the store.
What I want is just access to the store that I created without subscribing to updates.

I can of course export it from where I created it. Is that the best way?

@markerikson

This comment has been minimized.

Copy link
Contributor

commented Dec 17, 2018

What are you actually trying to accomplish?

@badtant

This comment has been minimized.

Copy link
Author

commented Dec 17, 2018

I want to read a value from the store in componentWillUnmount.
So I want access to the store without subscribing to any updates.

Previously I got access with this.context.store.getState()

@markerikson

This comment has been minimized.

Copy link
Contributor

commented Dec 17, 2018

Per the React docs on using context, you would either need to add a contextType field to your component so that you can access the context value as this.context, or have a wrapper component that renders a <Context.Consumer>, extracts the store, and passes it as a prop to your own component.

What kind of value are you needing to read from the store on unmount? Why not just connect the component, and extract that value in mapState as normal?

@badtant

This comment has been minimized.

Copy link
Author

commented Dec 17, 2018

  • contextType is not supported with react-redux 6.0.0 if I understood correctly
  • mapState works but will subscribe me to updates I don't need
  • Context.Consumer also works but did also subscribe me to updates

I'm just trying to think as performant as possible. Hence not wanting to subscribe if I don't need all the updates.

@markerikson

This comment has been minimized.

Copy link
Contributor

commented Dec 17, 2018

contextType is a React thing, not a React-Redux thing, and should work fine.

As I asked, what kind of value are you trying to use? Is it something that you expect will be changing frequently? Do you have specific reasons why you think connecting to get this value will be a performance issue? Why do you only need this in componentWillUnmount?

My general reaction here is that you're over-thinking the performance implications, but I can't say for sure because I don't know the specifics of your app and what you're trying to do.

@badtant

This comment has been minimized.

Copy link
Author

commented Dec 17, 2018

Ok. I used contextType before upgrading to 6.0.0. When I upgraded it stopped working... The release notes said this:
"Any library that attempts to access the store instance out of legacy context will break, because we now put the store state into a <Context.Provider> instead."

The value I want to read is a string that does change quite a lot and in this component I only need it when it unmounts. It's used for statistics tracking in this case.
Maybe I'm overthinking but I always try to minimize the number of renders in my components. And since I got my case working as I wanted before I want it to work the same way now when upgrading.

@markerikson

This comment has been minimized.

Copy link
Contributor

commented Dec 17, 2018

Note that contextTypes and contextType are not the same thing.

React defines legacy context using syntax like:

class MyComponent extends React.Component {}

MyComponent.contextTypes = {
    a : PropTypes.string,
    b : PropTypes.object
}

When the new context API was released, it originally could only be used via a render-props API:

<MyContext.Consumer>
{ (contextValue) => {
    // do stuff with the context value here
});
</MyContext.Consumer>

To help with the migration from old context to new context, the React team added a new way to access new context in 16.6 called contextType:

class MyClass extends React.Component {
  static contextType = MyContext;
  componentDidMount() {
    let value = this.context;
    /* perform a side-effect at mount using the value of MyContext */
  }
}

So, you should be able to do:

class MyComponent extends React.Component {
    static contextType = ReactReduxContext;

    componentWillUnmount() {
        const storeState = this.context.store.getState();
        // do something with the store state here
    }
}
@badtant

This comment has been minimized.

Copy link
Author

commented Dec 17, 2018

Ahh, didn't know about that way :) Will try it first thing tomorrow.
Thanks!

@badtant

This comment has been minimized.

Copy link
Author

commented Dec 18, 2018

contextType seem to work the same way as Context.Consumer in this case. meaning I get updates.
this.context now includes both store and storeState. is there a way to only get store?

@markerikson

This comment has been minimized.

Copy link
Contributor

commented Dec 18, 2018

No, the React-Redux <Provider> puts both of those into the context.

@timdorr

This comment has been minimized.

Copy link
Member

commented Dec 18, 2018

If you want that, you can just make your own context:

// StoreContext.js
import React from 'react'

export const StoreContext = React.createContext()

export default StoreContext
// app.js

import StoreContext from './StoreContext'

const store = createStore(reducer)

ReactDOM.render(
  <Provider store={store}>
    <StoreContext.Provider value={store}>
      <App />
    </StoreContext.Provider>
  </Provider>,
  root
)

The new API is really simple 👍

@tibbus

This comment has been minimized.

Copy link

commented Feb 6, 2019

You can use ReactReduxContext from 'react-redux' :
Docs and example here : https://react-redux.js.org/api/provider

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
4 participants
You can’t perform that action at this time.