is there any way to access the parent component instance in React? - reactjs

I know it's not a functional approach to be able to do something like this.parent in a React component, and I can't seem to find any properties on a React component instance that lead to the parent, but I'm just looking to be able to do some custom things where I need this.
Before anyone wastes their time explaining it's not the functional React "way," understand that I need this because of the following I'm trying to achieve:
Build a transpiler for Meteor's Spacebars templating engine, whose rendering model does take into consideration parent components/templates.
I've already built a transpiler that modifies the output jsx to achieve this. I do this by passing in parent={this} in all child components composed. However, after the fact it occurred to me that maybe I simply don't know of something that will give me a way to access the parent component instance without additional transpilation modifications.
Any tips would be much appreciated.

There's nothing wrong if you need to access the parent's props and functions from the children.
The point is that you should never use React internals and undocumented APIs.
First of all, they are likely to change (breaking your code) and, most importantly, there are many other approaches which are cleaner.
Passing props to children
class Parent extends React.Component {
constructor(props) {
super(props)
this.fn = this.fn.bind(this)
}
fn() {
console.log('parent')
}
render() {
return <Child fn={this.fn} />
}
}
const Child = ({ fn }) => <button onClick={fn}>Click me!</button>
Working example
Using context (if there's no direct parent/child relation)
class Parent extends React.Component {
constructor(props) {
super(props)
this.fn = this.fn.bind(this)
}
getChildContext() {
return {
fn: this.fn,
}
}
fn() {
console.log('parent')
}
render() {
return <Child fn={this.fn} />
}
}
Parent.childContextTypes = {
fn: React.PropTypes.func,
}
const Child = (props, { fn }) => <button onClick={fn}>Click me!</button>
Child.contextTypes = {
fn: React.PropTypes.func,
}
Working example

Update for React 0.13 and newer
Component._owner was deprecated in React 0.13, and _currentElement no longer exists as a key in this._reactInternalInstance. Therefore, using the solution below throws Uncaught TypeError: Cannot read property '_owner' of undefined.
The alternative is, as of React 16, this._reactInternalFiber._debugOwner.stateNode.
You've already recognized that this is not a good thing to do almost always, but I'm repeating it here for people that don't read the question very well: this is generally an improper way to get things done in React.
There's nothing in the public API that will allow you to get what you want. You may be able to get to this using the React internals, but because it's a private API it's liable to break at any time.
I repeat: you should almost certainly not use this in any sort of production code.
That said, you can get the internal instance of the current component using this. _reactInternalInstance. In there, you can get access to the element via the _currentElement property, and then the owner instance via _owner._instance.
Here's an example:
var Parent = React.createClass({
render() {
return <Child v="test" />;
},
doAThing() {
console.log("I'm the parent, doing a thing.", this.props.testing);
}
});
var Child = React.createClass({
render() {
return <button onClick={this.onClick}>{this.props.v}</button>
},
onClick() {
var parent = this._reactInternalInstance._currentElement._owner._instance;
console.log("parent:", parent);
parent.doAThing();
}
});
ReactDOM.render(<Parent testing={true} />, container);
And here's a working JSFiddle example: http://jsfiddle.net/BinaryMuse/j8uaq85e/

Tested with React 16
I was playing around with something similar using context, tho to anyone reading this, for most usual cases, accessing the parent is not advised!
I created a holder that when used, would always have a reference to the first holder up the display list, so its 'parent' if you will. Looked something like this:
const ParentContext = React.createContext(null);
// function to apply to your react component class
export default function createParentTracker(componentClass){
class Holder extends React.PureComponent {
refToInstance
render(){
return(
<ParentContext.Consumer>
{parent => {
console.log('I am:', this, ' my parent is:',parent ? parent.name : 'null');
return(
<ParentContext.Provider value={this}>
<componentClass ref={inst=>refToInstance=inst} parent={parent} {...this.props} />
</ParentContext.Provider>
)}
}
</ ParentContext.Consumer>
)
}
}
// return wrapped component to be exported in place of yours
return Holder;
}
Then to use it you would pass your react component to the method when you export it like so:
class MyComponent extends React.Component {
_doSomethingWithParent(){
console.log(this.props.parent); // holder
console.log(this.props.parent.refToInstance); // component
}
}
// export wrapped component instead of your own
export default createParentTracker(MyComponent);
This way any component exporting the function will get its parent's holder passed in as a prop (or null if nothing is further up the hierarchy). From there you can grab the refToInstance. It will be undefined until everything is mounted though.

Related

Is it ok to use a wrapper component to pass props in React?

export function injectProps() {
const injects = {store: new Store()}; // some store
return function (Component) {
return class Proxy extends React.Component {
render() {
return React.createElement(Component, {
...injects,
...this.props,
});
}
};
}
}
Is it ok to use this instead of Redux or Context API with React?
Update: I think I missed to point out my expectation. I'm actually passing some service(http, localStorage) to childrens only when they asks for it. It's not only about the store as services don't have any state. But I also need to pass store through it.
https://pastebin.com/G3PgVxLn
Maybe this tweet by the Dan Abramov (React maintainer) might help.
I understand it was probably not the point of the article. But I see
people reaching for Context or Redux because they don’t realize
components can take any children — and that often removes the need for
deep prop passing. Would be great to highlight!
And Dave Ceddia posted a relavant React documentation link.
Composition vs Inheritance
You can read upon those two.
And here is a demo Nicolas Marcora created to show me how to pass properties to child/children.
You can pass props to children using React.cloneElement(child,...
Working demo on StackBlitz.
export default class WithMouse extends React.Component {
state = { x: 0, y: 0 }
handleMouseMove = event => { ... }
render() {
const { children } = this.props
const childElements = React.Children.map(children, child =>
React.cloneElement(child, {
mouse: this.state,
onMouseMove: this.handleMouseMove
})
)
return <div>
{ childElements }
</div>
}
}
You can use WithMouse class to pass props downward to all children and use it like following.
class App extends Component {
...
render() {
return (
<WithMouse>
<MouseTracker />
</WithMouse>
);
}
}
MouseTracker has access to props passed from WithMouse so you can just use it without directly passing it manually.
You can probably go further and pass all props instead of a few (mouse, onMouseMove)

Benefits of composition over inheritance in React

I'm having a hard time substituting inheritance for composition in React. I'll try to explain the problem posed and my current solution, based on inheritance which is discouraged in the React style guide.
First, I define common state and methods in a super component:
export default class SuperComponent extends Component {
constructor(props) {
super(props);
this.state = commonState;
}
foo() {
this.setState({a: 3});
}
render() {
return (
<div>
{this.getContent()}
</div>
)
}
}
Then I make subcomponents with potentially more state and methods. These should also have access to the state of the supercomponent though:
export default class SubComponent1 extends SuperComponent {
constructor(props) {
super(props);
this.state = Object.assign(this.state, subComponent1State);
}
bar() {
this.setState({b: 7});
}
getContent() {
return (
<div>
I'm subcomponent 1
</div>
)
}
}
export default class SubComponent2 extends SuperComponent {
constructor(props) {
super(props);
this.state = Object.assign(this.state, subComponent2State);
}
bar() {
this.setState({c: 1});
}
getContent() {
return (
<div>
I'm subcomponent 2
</div>
)
}
}
When I try to convert this into an composition based approach I get this:
export default class SuperComponent extends Component {
foo() {
this.props.setStateMethod({a: 3});
}
render() {
return (
<div>
<div>
{this.props.text}
</div>
</div>
)
}
}
export default class SubComponent1 extends Component {
constructor(props) {
super(props);
this.state = Object.assign(commonState, subComponent1State);
}
bar() {
this.setState({b: 7});
}
render() {
return (
<SuperComponent
text={"I'm subcomponent 1"}
setStateMethod={this.setState}
subComponentState={this.state}
/>
)
}
}
export default class SubComponent2 extends Component {
constructor(props) {
super(props);
this.state = Object.assign(commonState, subComponent2State);
}
bar() {
this.setState({c: 1});
}
render() {
return (
<SuperComponent
text={"I'm subcomponent 2"}
setStateMethod={this.setState}
subComponentState={this.state}
/>
)
}
}
Is this a good way to go about converting the inheritance based solution to a composition based one? Isn't the inheritance based one better since common and differentiated state are better separated? In the composition based solution, one has to define common state in every sub component on initialisation.
First off, you should read React's Team response on the matter.
The code is pretty vague, so I can't tell if your case is really special, but I doubt it, so let me tackle the general consensus:
Inheritance and Composition are, in a vacuum, equally useful. In some languages or projects, you'll prefer a common class to inherit from, than a dozen functions to import and call, but in React, mainly because it's component-centric approach, the oposite is true.
Composition keeps React about just two things: props and state. You trust what you receive, act in a predictable way and reflect both props and state in what you render. If you need to change slightly what you render, you can send down different props, maybe even make a component that wraps the first one for that specific use. That component can even have some logic on it's own, and pass it down through render props so you can control the result with even more precision. If you need to wrap different components with this logic you can make a HOC and wrap any component easily. At that point you can make dozens of components that return different things to the same props and can switch between a library of components to display the data and to handle it.
Although things like Render props or HOCs look like different things, they are just techniques that use the already existing component logic and apply it in ways that let you reuse code and still make sense within React. Is it a good solution? Well, it works, but you end up in wrapping hell and juggling twenty concepts that are pretty much the same. That's why there is now a proposal for a paradigm changing new feature that is midway between inheritance and composition. But composition still makes less sense in the React way of doing things.
At the end of the day is just a different way of looking at the same problem. Composition just works better with React, and gives you more control in render to mix and match what you need.
Again, if you have a practical example I could give you a better explanation applying different React techniques, but with your current one, clearly there isn't a good or bad way to do it, since it does nothing. This takes some time tinkering more than an explanation.
I don't think your solution is the best composition-based solution in this case. Since you want the subcomponents to have their own state (and I assume they will have their own logic), I would use a hoc like this:
// hoc.js
const withSuper = (SubComponent) => {
class WithSuper extends React.Component {
constructor(props) {
super(props);
this.foo = this.foo.bind(this);
}
foo() { // could also receive a value
this.props.setState({ a: 3 });
}
render() {
// Passes to the SubComponent:
// the state.a as a prop
// function foo to modify state.a
// the rest of the props that may be passed from above
return (
<SubComponent
a={this.state.a}
foo={this.foo}
{...this.props}
/>
)
}
}
return WithSuper;
};
// SubComponent1.js
class SubComponent1 extends Component {
constructor(props) {
super(props);
this.state = { b: 0 }; // or anything else
}
bar() {
this.setState({b: 7});
}
render() {
// to access the 'a' value use: this.props.a
// to modify the 'a' value call: this.props.foo()
return (
<div>
I'm subcomponent 1
</div>
);
}
}
export default withSuper(SubComponent1);
The SubComponent2 would also be wrapped: withSuper(SubComponent2), so it could also access a and foo() props.
I think this solution is better, because the hoc "Super" encapsulates the behavior of a, and the sub-components only have to worry about modifying their specific state.

what is the alternative for ReactDOM.findDOMNode() as it is deprecated now?

I have an old code which is using findDOMNode().
Here is my code, where someComponent1 and Expand is already imported.
Here I have some doubt the code I have written with findDOMNode() is working perfectly fine but as it is deprecated now I want to remove it. I have gone through many document and found to use portals or refs instead of this.
I have a understanding that if I am using ref then the variable get bind to that also has an access to the DOM element, but I guess I am wrong as it is working in that way. Can someone please correct my understanding on this
class classA extends Component {
componentDidMount() {
new Expand(ReactDOM.findDOMNode(this.expand))
// new Expand(this.expand)
}
render(){
return(
<someComponent1 className={style.container} ref={e => this.expand= e}/>
)
}
}
As per this github issue and ReactDocs,ReactDOM.findDOMNode is not deprecated but its usage is discouraged and should only be used as an escape hatch. In order to replace it, you need to specify the ref on the DOM element which in your case would look like
class classA extends Component {
componentDidMount() {
new Expand(this.expand)
}
render(){
return(
<SomeComponent1 className={style.container} innerRef={e => this.expand= e}/>
)
}
}
class SomeComponent1 extends React.Component {
render() {
return <div ref={this.props.innerRef}>Hello</div>
}
}

react component - parent child interaction; component Lifecycle

I am developing a simple browser app to get some specific data from the user.
I have several components to simplify the proccess of collecting that data, but I am currently rethinking my way of rendering this component.
Basically, i have my main component, which uses state to keep track of which component to render.
I am doing this for almost all of my components.
Also, i also have a function inside the parent component, that i pass to the child component via props, and that is used as a callback to pass the child state to its parent, when that component is no longer useful.
class Main extends React.Component {
constructor(props){
this.state = {
renderA: true,
renderB: false,
childState: null
}
}
collectState(state){
this.setState({
childState: state
});
}
render() {
let content = null;
if(this.state.renderA === true){
content = <ComponentA />
} else {
content = <ComponentB />
}
return(
<div>
{content}
</div>);
}
}
So, using the above example, the child would be something like this
class ComponentA extends React.Component {
constructor(props){
super(props);
this.state = {
stop: false,
usefullInfo: null
}
destroy() {
this.props.collectstate(this.state.usefullInfo)
}
render(){
render something (like a Form) untill this.state.usefullInfo is set;
in that case, set this.state.stop true which will call destroy, passing the usefull information to parent
}
}
So, this method works for me, but i can see clearly that most probably this is not the way to do this.
At this point my question are:
1) how can I stop rendering a component without having to track it with some property like this.state.stop ?
2) if i want to render 2 different components, like in the main component, do I always have to keep a renderA and renderB property on state, to render one or another?
3) is there a better way to pass information from child to parent? i am currently using a callback function passed via props from parent to child, and i am invoking that callback when the component has done its purpose
4) any general suggestions on how to improve the quality of the above code?
Thank you for you help :)!
Your example works fine, but in React it is recommended to lift state up when handling data from multiple children (source). So I would recommend to keep the sate of every children in the parent, and pass props with values and handlers to the children.
Here's a sample app you can check. The form components handle the case you want to implement.
To answer your questions:
The parent component should decide, based on its own state, whether to render a child component or not.
It's not needed to keep variables on state about what component to render. that should be computed in render() based on the parent's state
Yes, callback are the recommended way to pass information to parents
Code quality looks good. You can always do good with tools like prettier or ESlint.
Here's an example:
class Main extends React.Component {
constructor(props) {
this.state = {
stateA: '',
stateB: '',
};
}
handleStateChange(name, value) {
this.setState({
[name]: value,
});
}
render() {
const { stateA, stateB } = this.statel;
const shouldRenderA = !stateA;
if (shouldRenderA) {
return <ComponentA value={stateA} onChange={value => this.handleStateChange('stateA', value)} />;
}
return <ComponentB value={stateA} onChange={value => this.handleStateChange('stateB', value)} />;
}
}
class ComponentA extends React.Component {
render() {
const { value, onChange } = this.props;
return <input type="text" value="value" onChange={onChange} />;
}
}

Recommended way to inherit nodeJs's request Object in ReactJS

What the the best way to inherit a complex Object or class down to every ReactJS-Component ?
As described on their documentation its not recommended to use context and I guess using the prop will also not the best solution.
This is our case:
Edit: Maybe a better example is when we try to inherit the request object from router into the 20th level of children for SSR reasons
We are using a Router which works on client and also for SSR. For every route which gets rendered we need on client and server a generated class to work with. So one solution should look like this:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myAwesomeObject = new AwesomeClass({/* some settings */});
}
getChildContext() {
let { myAwesomeObject } = this;
return {
myAwesomeObject
};
}
render(){
return (
<span><ComponentLevel1 /></span>
);
}
}
const ComponentLevel1 = () => {
return (
<div>
<ComponentLevel2 />
</div>
);
};
const ComponentLevel2 = () => {
return (
<div>
<ComponentLevel3 />
</div>
);
};
......
const ComponentLevel20 = (props) => {
content = this.context.myAwesomeObject.doSomeThingWithProps(props);
return (
<div>
{content}
</div>
);
};
In this example I am now able to use the awesomeObject in every Component I will render but the context is not recommended by ReactJS:
https://facebook.github.io/react/docs/context.html
So my question now is: What is the best recommended way to inherit classes like that down to all components ?
I know: on client this is not a problem because I can create the object once and use it on client global but on server (SSR) I also need access to the created class. And recreating the object every time I need it in another component seems not to be the best solution - also not to add this class to any component as property - right ?
EDIT
I have edited the code snippet to show that it maybe has a case where the 20th level of my children needs access to the instance. With context it would work like in my example but ReactJS says its not recommended. So the other solution would be to add the class to the properties of my children - 20 levels down - but is this really the best recommended solution to solve this ?
What about composition? (https://facebook.github.io/react/docs/composition-vs-inheritance.html)
class SomeComponent extends React.Component {
render() {
return(
<SomeOtherComponent {...this.props} />
)
}
}
By passing all the props down to different component (including it's children) you can easily customize child component behavior.

Resources