React re-renders component unnecessary after prop change - reactjs

So I have reducer autocomplete that stores all options loaded throught react-select. I also have two components - <Parent /> and <Modal />. Both of them are connected to redux state to receive autocomplete props, because both of them have its own <AsyncSelect /> component.
Select that is children of <Parent /> component, receives options from reducer: autocomplete.labels. Second Select component that is children of <Modal />, receives options from reducer: autocomplete.differentLabels.
Now, when I'm using Select that is children of Modal, whole Parent component is re-rendered, even if there is no jsx dependent on autocomplete. Is this expected behavior? Because of this re-rendering, performance decreases.
Maybe should I divide labels and differentLabels into separate reducers?

A possible solution can be to use the shouldComponentUpdate to compare the current props to previous props and do some logic there to prevent unnecessary update.
shouldComponentUpdate(nextProps, nextState) {
if (this.props.myProp !== nextProps.myProp) {
// Your logic
return false;
}
return true;
}

Related

How to get react grand-child node to render when child is out of my control

I have a react component which uses a 3rd party library Component as a Child node. The Grand children (or the children of the 3rd party libary) are under my control. When my component receives new props it re-renders, however the 3rd party component seems to stop my components grand-children from re-rendering also, even though the props my component received, are passed to the non-re-rendering components directly
If I remove the 3rd party component then my component re-renders as do the grand-children.
render() {
<div>
<ThirdPartyComponent props={blah}>
{this.props.products.map(prod => <MyGrandChildrenComponents product={prod} />
</ThirdPartyComponent>
</div>
}
A concrete example can be found on this code sandbox: codesandbox.io/s/silly-grass-7frlx
I'd expect my MyGrandChildrenComponents component to get updated when this.props.products changes... Any hints?
This can happen if ThirdPartyComponent is a stateful component and is not handling its prop updates correctly. One way to force a re-render is to add a key prop to your ThirdPartyComponent and update its value when a re-render is needed.
render() {
<div>
<ThirdPartyComponent key={something-that-changes-when-rerender-needed} props={blah}>
{this.props.products.map(prod => <MyGrandChildrenComponents product={prod} />
</ThirdPartyComponent>
</div>
}
If ThirdPartyComponent is a PureComponent it should re render (and so re render its children) when one of its props changes so you can try:
render() {
<div>
<ThirdPartyComponent props={blah} products={this.props.products}>
{this.props.products.map(prod => <MyGrandChildrenComponents product={prod} />
</ThirdPartyComponent>
</div>
}
To trigger re renders when this.props.products changes.
But any prop should do.
If ThirdPartyComponent has a custom implementation of shouldComponentUpdate, then you will have to find the specific prop which triggers update if it exists.

Pass data between siblings without Redux

Consider the following component tree
<Header />
<SearchBar />
<ProductList />
<Product />
In the SearchBar component I want to catch the value of an input and send that value to ProductList to dynamically render Product components based on the value received.
Is there a way to communicate between SearchBar and ProductList without the need of a component that wraps both of them or without Redux ?
According to React's page "React is all about one-way data flow down the component hierarchy" which means that data passing horizontally should be avoided.
In your case you could have a parent component that render <SearchBar/> and <ProductList/>based on state. For example, whenever the user enter with a value in <SearchBar> it changes the state on the parent component, and consequently <ProductList> will be rendered again.
As Osman said, you could pass the value of the SearchBar into a state and then from the state into the Product using a function.
handleChange(event) {
this.setState({
newProduct: event.currentTarget.value
)}
}
render() {
return(
<SearchBar onChange={this.handleChange} />
<Product content={this.state.newProduct} />
);
}
Make sure you don't forget to bind the function in the constructor.

ReactDOM.render does not update containers props

I have a container containing some html with a <div id="ID"></div>. I have a react stateful component that I want to render in that div using
React.render(<ChildComponent data={this.props.data} />, document.getElementById('ID'))
When I call an action in childcomponent and udate the redux state, the props of the parent container do not update, only the ChildComponent re-renders with old values. Those props get updated when I refresh the page.
What is the solution to this ? Is there any other way to render React component in html so that the props can be updated with new props ?
Can you share your code for <ChildComponent> and its parent? There are a number of things you might be doing wrong but the thing that stands out is that it looks like you're rendering separately from its parent instead of as a child "prop" of its parent, like so:
<ParentComponent>
<ChildComponent />
</ParentComponent>
The official docs also have a lot of examples on how to get started: https://facebook.github.io/react/docs/hello-world.html
Hope this helps!

REACT Warning Unknown props parsing to child component [duplicate]

I've built my own custom react-bootstrap Popover component:
export default class MyPopover extends Component {
// ...
render() {
return (
<Popover {...this.props} >
// ....
</Popover>
);
}
}
The component is rendered like so:
// ... my different class ...
render() {
const popoverExample = (
<MyPopover id="my-first-popover" title="My Title">
my text
</MyPopover >
);
return (
<OverlayTrigger trigger="click" placement="top" overlay={popoverExample}>
<Button>Click Me</Button>
</OverlayTrigger>
);
}
Now, I want to add custom props to MyPopover component like that:
my text
And to use the new props to set some things in the popover
for example -
<Popover {...this.props} className={this.getClassName()}>
{this.showTheRightText(this.props)}
</Popover>
but then I get this warning in the browser:
Warning: Unknown props popoverType on tag. Remove these props from the element.
Now, I guess that I can just remove the {...this.props} part and insert all the original props one by one without the custom props, but In this way I lose the "fade" effect and also it's an ugly way to handle this problem. Is there an easier way to do it?
Updated answer (React v16 and older):
As of React v16, you can pass custom DOM attributes to a React Component. The problem/warning generated is no longer relevant. More info.
Original answer (React v15):
The easiest solution here is to simply remove the extra prop before sending it to the Popover component, and there's a convenient solution for doing that.
export default class MyPopover extends Component {
// ...
render() {
let newProps = Object.assign({}, this.props); //shallow copy the props
delete newProps.popoverType; //remove the "illegal" prop from our copy.
return (
<Popover {...newProps} >
// ....
</Popover>
);
}
}
Obviously you can (and probably should) create that variable outside your render() function as well.
Basically you can send any props you want to your own component, but you'd have to "clean" it before passing it through. All react-bootstrap components are cleansed from "illegal" props before being passed as attributes to the DOM, however it doesn't handle any custom props that you may have provided, hence why you have to do your own bit of housekeeping.
React started throwing this warning as of version 15.2.0. Here's what the documentation says about this:
The unknown-prop warning will fire if you attempt to render a DOM element with a prop that is not recognized by React as a legal DOM attribute/property. You should ensure that your DOM elements do not have spurious props floating around.
[...]
To fix this, composite components should "consume" any prop that is intended for the composite component and not intended for the child component.
For further reading, check this page from the official react site.

Add custom props to a custom component

I've built my own custom react-bootstrap Popover component:
export default class MyPopover extends Component {
// ...
render() {
return (
<Popover {...this.props} >
// ....
</Popover>
);
}
}
The component is rendered like so:
// ... my different class ...
render() {
const popoverExample = (
<MyPopover id="my-first-popover" title="My Title">
my text
</MyPopover >
);
return (
<OverlayTrigger trigger="click" placement="top" overlay={popoverExample}>
<Button>Click Me</Button>
</OverlayTrigger>
);
}
Now, I want to add custom props to MyPopover component like that:
my text
And to use the new props to set some things in the popover
for example -
<Popover {...this.props} className={this.getClassName()}>
{this.showTheRightText(this.props)}
</Popover>
but then I get this warning in the browser:
Warning: Unknown props popoverType on tag. Remove these props from the element.
Now, I guess that I can just remove the {...this.props} part and insert all the original props one by one without the custom props, but In this way I lose the "fade" effect and also it's an ugly way to handle this problem. Is there an easier way to do it?
Updated answer (React v16 and older):
As of React v16, you can pass custom DOM attributes to a React Component. The problem/warning generated is no longer relevant. More info.
Original answer (React v15):
The easiest solution here is to simply remove the extra prop before sending it to the Popover component, and there's a convenient solution for doing that.
export default class MyPopover extends Component {
// ...
render() {
let newProps = Object.assign({}, this.props); //shallow copy the props
delete newProps.popoverType; //remove the "illegal" prop from our copy.
return (
<Popover {...newProps} >
// ....
</Popover>
);
}
}
Obviously you can (and probably should) create that variable outside your render() function as well.
Basically you can send any props you want to your own component, but you'd have to "clean" it before passing it through. All react-bootstrap components are cleansed from "illegal" props before being passed as attributes to the DOM, however it doesn't handle any custom props that you may have provided, hence why you have to do your own bit of housekeeping.
React started throwing this warning as of version 15.2.0. Here's what the documentation says about this:
The unknown-prop warning will fire if you attempt to render a DOM element with a prop that is not recognized by React as a legal DOM attribute/property. You should ensure that your DOM elements do not have spurious props floating around.
[...]
To fix this, composite components should "consume" any prop that is intended for the composite component and not intended for the child component.
For further reading, check this page from the official react site.

Resources