Is there a way to access the React tree down a component from within it?
For instance when I use the React-devtool extension I am able to navigate along the React tree. Is it possible to do such navigation from within the code of a component to know everything below it?
I know about children, but it does not work when parents components simply render children components, ie in Parent component I have something like
render() {
<Child1 />
}
then in Child1 component I have
render() {
<Child2 />
}
etc.
and I'd like to know from Parent that there is below a Child1 and then a Child2.
I have had a look at this._reactInternalInstance._instance._renderedComponent._currentElement where I can see that, for instance, Parent renders a Child1. But from this I cannot go further to see what Child1 renders.
I managed to solve a similar problem (needed to access state of a foreign Component's child) with:
return <Child ref={this.childRef} />
this.childRef.current._reactInternalFiber.child.child.memoizedState;
Hope it helps & YMMV ;)
Related
I have a Parent React Native component which is composed of three children components, Header, Body, and Footer. This is how it is arranged inside a file MyScreen.js:
<Container> // I am using NativeBase Container
<Header />
<Body />
<Footer />
</Container>
Definitions of these three children components are contained in separate files, e.g. Body.component.js, and so on.
I want to access an array data structure Foo contained in a different file FooArray.js, and it is imported by both Body and Footer components. Foo is manipulated inside the Body component (I push() objects to this array here) and its length Foo.length is displayed in the Footer component.
How can I make sure that whenever a new object is pushed to Foo in the Body component, its new length is immediately reflected in the separate Footer component?
Any ideas, regarding not only the expected solution but also optimal re-structuring of the project files if needed, are appreciated.
React solves this problem with state.
You import your data (foo) into a top level component (Container) and assign it to the state. Then you can pass the state down to children components as props.
All the children components can use these props and will automatically update if the prop changes.
If you want to make changes to the state from within the children components, you should pass handler functions (defined in the parent component) to the children components as props.
I ran into an issue which I do not know how to "properly" solve.
I have two components, let's call them parent and child.
child component is "generated" by a call to a function that creates it, let's call this function child creator.
parent component has a button which shows/hides the child but is also suppose to .focus() the HTML dom node which is what the child is. Now the show/hide I implemented via the state, but I do not know how to apply javascript's .focus() onto the child's HTML dom node.
There is also a small catch... the child component is being "generated" and "returned" by a call to a plain old javascript function, let's call it createChild.
This is due to the fact that child component needs to be vastly different based on what the parameters that were passed are, however, it also needs to be reused throughout the application so the createChild functions make sure that all the child components are the same, given the same inputs.
I tried passing ref to the creator, however since ref is not a prop, it is not accessible. What is the proper way to "grab" the children's dom nodes in order to .focus() them when the button is clicked since I cannot pass a ref?
Code sandbox link: https://codesandbox.io/s/lyj6x2948m
Yes, child ref is accessible since it is part of real DOM. I made a simple example with two nested components, check it out:
class Parent extends React.Component {
focusRef(ref) {
ref.focus();
}
render() {
return <Child focusRef={this.focusRef} />
}
};
class Child extends React.Component {
render() {
return (
<button
ref={childRef => this.childRef = childRef}
onMouseEnter={() => this.props.focusRef(this.childRef)}
>
When mouse enters, i get focused
</button>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById("root")
);
*:focus {
outline: 2px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root" />
Also, I strongly recommend further reading on react docs:
Okay for everyone wondering, I found a solution to the problem.
To begin with, the issue was not in the ref passing (at least not explicitly), but rather in a way controls are being created (which doesnt allow the ref to be passed).
The controlCreator function is a good old simple javascript function, and it was being used to provide a type for a React.createElement because the result of calling the controlCreator ends up being a react component.
I have however came to an understanding of why this is wrong and have instead proceeded to generate my child elements by the controlCreator and then using React.cloneElement to inject them with a ref. This way, the element is being cloned within a parent and can thus be referenced by parent's methods.
A link to a working code sandbox
Is it considered bad practice to annotate the children of a react component with properties solely to provide information to said component? For example suppose I have a navigation component which requires a name for each child component.
<Nav>
<Child name="child1"/>
<Child name="child2"/>
</Nav>
Here the 'name' property is only used by Nav. The only other way I can think of accomplishing this is by passing in an array of names as a property to nav where each element contains the name of the corresponding child index, but this is fragile and less declarative. Alternatively I could provide a map of names to child elements to nav instead of relying on props.children but this seems ugly. Doing things this way feels natural but also unreactish, am I breaking some best practice or idiom? If so, how should I implement something like this?
As a general principle, I only add props to components that require them. So in your case, I would only add the name prop if the Child component required it. It would be quite confusing to see a prop on a component in the parent element, yet not find the child component using it.
An alternative to your approach would be to create a wrapping child component. You could create a NavItem wrapper that is used as such:
<Nav>
<NavItem name="child1">
<Child />
</NavChild>
<NavItem name="child2">
<Child />
</NavChild>
</Nav>
The NavItem doesn't need to render any mark up, instead it could just render the children.
const NavItem = (props) => props.children;
This way, you parent Nav component gets a child with the props it needs, and you don't dirty the Child components with props it doesn't expect.
So lets assume I have something simple that has a render with a return of:
<Sample>
{this.props.children}
</Sample>
Now lets call this component Example and lets pass some child Props to it:
<Example>
<ChildA />
<ChildB />
</Example>
Now lets say I wanted to unmount (thus calling componentWillUnmount()) ChildB. How would you go about doing it?
If you don't want to render ChildB , there is nothing you can do from Example (Parent component which takes what you pass as props.children). It just shows whatever is written inside this component.
// Parent component
<div> {this.props.children} </div>
// somewhere in your code, you imported Parent component and
<Parent> Hello </Parent>
The point is this.props.children is only a way of saying if someone uses this component and if they put something in it , this component will show content where you put this.props.children. Nothing else. So this is not something Parent components do. They just show whatever the children are.
You question leads to another question : what if I want to show a component conditionally.
In this case you can do the following in your render methods :
{ yourConditionHere && <ComponentWhichWillMountIfConditionIsTrue /> }
As a result, if your condition passes , your parent component which accepts children, will show this component or vice versa.
I have a react component that contains a child list of components created using a map:
var listItems = model.arrayItems.map(function(item) {
return(<ChildComponent item={item}></ChildComponent>)
}, this);
And the component's render function then adds this list of child components:
return (
<div>
<h1>My items:<h1>
<ul>{listItems}</ul>
</div>
);
The problem is that the react component is not showing up in my browser when listItems is empty. However, if I resize the browser window, the component does show up. Does anyone have any advice on what might be causing this behavior?
So it did turn out to be an issue with ChildComponent. In fact, it seems to have been a CSS issue.
ChildComponent itself had a nested set of dynamically generated list items. These grandchild components had the CSS property for width set to 100%. Changing this property to "auto" fixed the issue.
My understanding is that when transitioning to a state in which the top-level list is empty, and given the way React is managing unmounted components, the grandchild component's CSS style of 100% (of parent element) somehow confuses the browser's rendering because its parent component is no longer mounted. If anyone knows the cause of this behavior in more depth, it would be great to hear a deeper explanation of this.