Annotating react children with props for the sake of the parent - javascript

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.

Related

How to keep the value of a variable current throughout multiple React Native components

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.

What is the preferred way to show/hide components in React.js?

What is the preferred way to toggle (show/hide) a component in React? To my knowledge, there are two ways to do this.
Solution 1:
Conditionally rendering the child component inside the render() method of the parent component.
{
this.state.showUserModal ?
<UsereModal onClose={this.onModalClose} user={this.state.selectedUser}/>
: null
}
Solution 2:
Using a property at the child component which inside its own render() method returns null or the children based on the boolean.
<UsereModal show={this.state.showUserModal} onClose={this.onModalClose} user={this.state.selectedUser}/>
The second solution causes to initialize the component only once (the constructor is called once) and the first solutions do not. I am having issues with this because in need to initialize my state based on the props inside the constructor, so I am forced to use solution 2. But what are the most React way to handle this?
In both cases if the parent state or props are changed both the parent and the child components will be re-rendered. Hence there is no performance gain of the second solution. But if the child component should not be shown in the second case it will be mounted and rendered (but not shown). Taking it into account I would suggest to use the first case.
If you want to persist the DOM elements in the UI, you should go using style binding or class binding:
<UsereModal style={{display: this.state.showUserModal ? 'block' : 'none'}} />
I think the first solution is better since you do not need to initiate UsereModal component with its own state that will control should component be shown or not. I prefer also jsx notation for conditional rendering
{
this.state.showUserModal && <UsereModal onClose={this.onModalClose} user=
{this.state.selectedUser}/>
}

Access React tree from within a component

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 ;)

How to bubble up an event to the very top parent React style?

I have a set of components app->page->list_container->list->item
My goal is to notify the app that click happened on item level.
If there is simple relation like parent->child I could use props and do something like: <Child onClick={this._onClick}> ... and then use this.props.onClick() to make a callback.
But what is the best native React-style receipt for doing the same trick with a tree of components? How to notify the app, that item was clicked without calling to Flux/Reflux, Elm and other supported libs?
Standard react way:
Passing onClick function as a prop down your component tree is the standard react-way of doing this.
In <app>:
<page onClick={this._onClick}>
In <page>:
<list_container onClick={this.props.onClick}>
Etcetera.
Or you could use:
<list_container {...this.props}>
To automatically pass down any prop from parent component to the child component.
In a deep tree, this can and will get quite tedious/ lot of work. React was not designed for this purpose.
React is made for (top-down) smart and fast component-tree rendering.
The frameworks for the flux pattern you mention are designed to handle the other interactive functions.
Alternative shortcut (not recommended):
A shortcut you could possibly use is to add a listener directly on the DOM, inside your <app> component, that handles the click event on the item:
In <app> component, add:
componentDidMount: function() {
var itemElementInDOM = document.getElementById('myItem');
itemElementInDOM.addEventListener('click',this._onClick);
}
And in your <item> component, give the item a (unique) id.
I would generally NOT recommend this:
In a typical react tree setup, the lower level components (like
<item>) may be rendered more than once, and then you would need
additional logic to ensure that each ID is unique.
You would also
need to add some additional smarts to make sure you remove the listener if the
item(s) in question are removed from the DOM.

React component not displaying if dynamically generated list items empty

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.

Categories

Resources