-
Notifications
You must be signed in to change notification settings - Fork 48.4k
Is there a way to access new context api within ComponentDidMount? #12397
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
Comments
Adding a example that I'm trying to have this working: https://codesandbox.io/s/l20yn296w7 EDIT: Following the guidelines from https://github.com/reactjs/rfcs/blob/master/text/0002-new-version-of-context.md#class-based-api |
This is how it can be achieved with new api. class BaseMapElement extends React.Component {
componentDidMount() {
console.log(this.props.context);
}
render() {
return null;
}
}
const MapElement = () => (
<Context.Consumer>
{context =>
<BaseMapElement context={context} />
}
</Context.Consumer>
) |
So the only way to access through Edit: Changed to |
The higher order component that redirecs to props is a good pattern,but for cases where don't want the extra component usually wat I do is store the context value on the component instance like: |
I'm facing the same dilemma. |
I’m pretty sure this is unsafe in async mode. Please don’t do this. cc @acdlite |
I agree with that. Would be nice to natively access through |
In general, using instance vars to be clever and cheat the normal data flow is going to cause problems in async. Just don’t. It’s a bit confusing today, because instance vars are the only way to do certain things, like timers. Before we release async we’ll publish clearer recommendations — and one day we’ll have a new component API that doesn’t rely so much on instances. tl;dr: Use a props indirection. And don’t worry too much about the extra component. |
How would this be unsafe (and in what way)? It's faily unclear in all this talk about async mode, what "unsafe" means. It's starting to feel like a boogyman who behavior is irrational and unpredictable, which doesn't fill folks with a lot of assurance in a system that is generally liked for it's straightforward, easily understandable, data flow model. I feels like components are back in pre 0.13 land where they are magic objects again. It's also easy to say "Just add another component", but that's often onerous, and introduces it's own category of bugs and challenges. I't starts to feel like folks have to invent abstractions over a react API in order to be "safe". |
sorry ^ if the above sounds annoyed/angry, i didn't intend that tone! on a phhhhooone |
It did sound angry haha but I get your point and I share your questions about how/why it will be unsafe |
I’m sorry, but we’ve been working on a guidance with specific suggestions for over a month now. Please give us time to collect and publish them as a blog post. It is also difficult to discuss without actual alphas to play with, which is also something we’ve been working hard on. So we have to either not say anything at all, or warn in advance about things that won’t work well. We err on the side of warning but I can see how it can look like we’re making it more difficult for you. I’m sure that once the code is out and you can play with it, you’ll see what we mean, and it’ll make more sense.
Did you get a chance to watch my talk? This will be a bit hard to explain if you haven’t seen the second part of it, because it wouldn’t be clear why we are doing this. So I’m asking you to watch it. I hope that my talk will convince you we’re aiming to solve a broad class of problems that plagued React since the beginning, and that these features are worth revisiting some assumptions we might have gotten used to. Assuming you’ve seen the talk, here’s a more specific explanation about this particular case. In order to be able to “suspend” rendering like I showed in the demo, React needs to be able to call In async, the rule of thumb is: only lifecycles like Now to the root of this issue. In async mode, React doesn’t make guarantees about when and in which order it calls the |
I understand it feels like it’s an extra wrapper, but it’s what makes the new context fast. If we didn’t have explicit wrapper nodes in the tree we wouldn’t be able to quickly “find” components that need to update. If you need to access context in lifecycle, take it as a prop. class Button extends React.Component {
componentDidMount() {
alert(this.props.theme);
}
render() {
const { theme, children } = this.props;
return (
<button className={theme ? 'dark' : 'light'}>
{children}
</button>
);
}
}
export default React.forwardRef((props, ref) => (
<ThemeContext.Consumer>
{theme => <Button {...props} theme={theme} ref={ref} />}
</ThemeContext.Consumer>
)); This is almost the same amount of lines as a |
Just wanted to second what Dan said that the child function / render prop approach is the official API for the new context- so please use it and let React worry about making sure it's fast. (It will be!)
The draft Strict Mode docs also touch on some of why mutating the instance (which is just another type of side effect) is dangerous in async mode. |
We have a experimental branch following the guidelines proposed here. Can anyone have a look to see if it make sense? https://github.com/commodityvectors/react-mapbox-gl/pull/11 |
I'm not familiar with this library, so I don't know if people ever make use of refs with its components- but if they did, the |
That make sense. Thanks for the reference. I'm going to close this issue for now. |
Just ran into this issue because I've been trying to see if I can achieve the same thing. So, from what I can gather from all this, it is not possible in the component which makes use of the
And that helper component
Wondering if this is going to cause any headaches down the line. Still feels like pretty standard React, if somewhat of a hack. |
There are some subtle differences that might make that approach a bad idea. For example, if 😄 I would suggest using a HOC approach for this instead: The only real downside to using a HOC for this sort of thing has been mitigated by the |
We took the approach like the react docs and what people said here. It is working well for us so far. https://github.com/commodityvectors/react-mapbox-gl/blob/master/src/Map.js#L63 |
Thanks for the feedback @bvaughn . At the moment I'm using it purely as a kind of state proxy component which adds / removes things from the UI depending on what is mounted within the context tree. Kind of like portals but within the React component tree. So not actually rendering children or dealing with refs at all. Will keep in mind if I need to do anything that interacts with refs. |
Hey everyone, I need context data in lifecycle methods. so, I followed the HOC approach after seeing the first few comments and passed the context data as props. I would really appreciate it if someone could share how I can write test cases for this scenario. I am using enzyme, enzyme-adapter-react-16 and jest but having some troubles in doing so. |
At the company I work for, we do the following (note, this might not be the consensus), we export the "naked" component as well and then import it in our tests and manually pass the props. E.g. // MyComponent.js
export class MyComponent extends Component { /* ... */ }
export default HOC()(MyComponent)
// MyComponent.spec.js
import { MyComponent } from '...'
// OtherComponents.js
import MyComponent from '...' Also, adding to this discussion, we encountered the same issue and created this https://www.npmjs.com/package/react-context-consumer-hoc that consumes multiple context. |
@AmnArora Why are you unable to write a unit test? What have you tried? What error are you seeing? |
@pgarciacamou Firstly thanks for the quick reply. Well, after not finding anything on the web and posting the query here. I came up with the same solution you mentioned. The Test cases are working now but this seems like a work around. I'll take a look at https://www.npmjs.com/package/react-context-consumer-hoc and discuss with my team. Thanks. 💯 |
@bvaughn The thing is earlier when I was using redux for state management, I shallow copied the Component and used dive() and instance() methods to get the instance of the component. But none of these methods were available when using context API. And when I wasn't using any of these methods I was getting the following error: unknown node with tag 12 |
Gotcha. Both of these sound like issues with the version of Enzyme you're using not properly supporting the new context API. That's unfortunate. |
I got massive distaste for |
Hi, is this problem solved? I has a scenario where I had 3 components. Creator, Display, Cells. Currently I need to pass the status if the item is being created or it has to display. I have used Cells in different locations so I need to pass the status as props separately. So I wanted to use context for status but problem is I wanted to modify context only if Display component was mounted. Can we achieve this is React's current versions? (I am using React 16.7) |
There have been a couple of comments above showing how to access |
Note that React 16.6 added a new |
Yeah, provided you only need to use a single context in your component– |
It does not. Even if a single context type is enough, Class.contextType breaks inheritance. The same is true about HOC. |
We are pretty explicit in our docs about recommending composition over inheritance for reusing code between components. Beyond that, I don't really understand what you're saying. The |
That's too broad... The case I am struggling with right now, is that I have a family of components with a bunch of common functionality needed to support their implementation. Everything is modelled by inheritance perfectly, except... context bits! Given that it seems I mess with context only in situations like this, context API is pretty frustrating.
Yes, this comment is slightly off-topic. |
Changing contextType with Context Class breaks redux store :/ |
Is there no way to compose contexts before assigning them to My read is that for now, if we want a component that can: a) Consume multiple contexts This means that we're stuck with the pattern described where the wrapper consumes the context and passes props to the child. I feel that an ideal situation would be that I could write something like this, and get the best of both worlds (i.e. multiple contexts available throughout the whole class):
Is there any way to do this? |
It works for render method, but not working for any other method....any idea ?? |
Hey there. We are migrating our projects from v15.x to v16.x, one of the tasks is to use the new context api In V15, we put those APIs into the old context api, and let each component to get it via something like class MyComp extends Component {
static contextTypes = {
insertCss: PropTypes.func
}
....
componentWillMount () {
// insert a style tag for this component
this.removeCss = this.context.insertCss(myStyles)
}
} In V15, we can put this in the componentWillMount. This will ensure the component get correct style before render. In V16, however, the componentWillMount is marked as unsafe and will be deprecated in future. However, seen from the document,
This usage (with context as a 2nd parameter) will be deprecated too. I tried the new context api, assigning MyComp.contextType = StyleContext class MyComp extends Component {
static contextType = StyleContext
constructor (props) {
super(props)
console.log(this.context) // undefined
}
} Is there any practical guide on how to use context in constructor? Any advice? |
You can do like this instead of using contextType class MyComponent extends React.Component {
render(){
const {
//props including context props
} = this.props;
return(<View />);
}
};
const withContext = () => (
<MyContext.Consumer>
{ (contextProps) => (<MyComponent {...contextProps}/>)}
</MyContext.Consumer>
);
export default withContext; |
For whoever like me are struggling to use it outside your render function just use the following in your sub-component: For example:
|
We are building a react mapbox gl module and we use clone and inject props today.
We were looking into using the 16.2.0 context api but I saw that it will have a new one on 16.3.0 but I can’t seem to find a way to read context details
On componentDidMount lifecycle (which makes sense for me to use on the map implementation).
Is there a way around this ?
The text was updated successfully, but these errors were encountered: