Have searched for a solution to this [seemingly] simple problem, but being relatively new to Node, haven't quite figured it out.
I need to set a prop on an imported Component prior to it rendering. The value for the prop is dynamic and based on the response of an API.
Based on what I've read, this should occur in the Constructor of my umbrella "App", but have few issues:
1) the Component throws an error when the prop value is set by API
2) I think this is because React attempts to render the Component before the API call completes
The Component renders without error if I manually set a valid value.
So, wondering how to grab the value and set the prop before the Component renders to avoid the error.
I can post a code sample, but have tried so many variations I'm not sure they'd be that useful.
Let me know if I am misunderstanding this.
You have two components, Component Parent and Component Child.
Component Parent gets information from an API, and sends it to Component Child.
Component Child renders depending on what you Parent sends to it
So, I believe the problem is that Child is not waiting for the API call to finish to render.
If I make an API call, I am not going to have the information for it immediately. You might want to handle the case where Child does not have the prop. To do that, you can call Child like this:
class Parent extends React.Component {
// Make the request to the API and handle the response
render(){
//Set the result of the API call to state.itemFromApiCall
return <div><Child item={this.state.itemFromApiCall} /></div>
}
}
And your Child component would look like this:
function Child (props){
if(!props.item)
return <span>Loading...</span>
//Then you have your component as you had before
}
On first Render, Child will not crash because it knows that prop.item might be undefined. Whenever you actually get the value of the API call, Child will behave as expected.
Hope it helps!
Related
As far as I know these are the scenarios when react calls the render() method provided shouldComponentUpdate() is not implemented.
when your component get mounted initially
when state got changed using this.setState()
when your component receives new props
when this.forceUpdate() get called.
Is there any other scenarios that I am missing?
Yes there's one more case I can think of. When parent component is re-render.
Every time a component is re-render all its children get re-render too. Unless you implement shouldComponentUpdate method in the children.
Hope it helps.
when context gets changed render gets called
I am current working with some complex stateful React components I installed through npm. For example, a react-bootstrap-table component. It accept data through its props. But it keeps a lots of states of its own, for example, which row is currently selected. I am adding a button, on clicking I would like to clear all the selected row information. Not having access to any API that can do that, I am wondering if I can totally reset the table component.
Right now I use a wrapper component that render the table based on a flag. It looks like:
class wrapper extends React.component{
render(){
if(this.props.flag==true) return <React-Table />;
else return null;
}
}
Now by toggling the flag, I can force a re-render of the table component with its original state.
I am wondering if there is a more straightforward way to do this?
After searching the react-boostrap-table API, it found a method reset (see docs):
Call reset to clean all the status on the table currently.
this.refs.table.reset(); // this.refs.table is a ref for BootstrapTable
To give a more general answer,
React does not have a general way to reset a component externally, the component should provide it if it's necessary. There are 2 ways for parent component to communicate with child component, through props, or not frequently, using ref to directly call a child method. Resetting is using the second way.
For react-bootstrap-table, there are reset() and cleanSelected() method you can call. How to call child component method.
I need to execute a piece of code after all grandchildren of a Component are rendered to scroll to one of the grandchildren. The structure looks like this:
`<GrandParent>
<IntermediateParent>
<IntermediateParent2>
<GrandChild/>
<GrandChild/>
<GrandChild/>
<GrandChild/>
</IntermediateParent2>
</IntermediateParent>
</GrandParent>`
The render method of GrandParent looks like this:
render() {
if (!this.props.listOfGrandchildren) { // still loading data from server
return <div>LOADING...</div>
}
return <IntermediateParent grandchildren={this.props.listOfGrandchildren} />
}
It is clear that using ComponentDidMount will clearly not work because of the children being mounted at a later time, after the data is loaded from the server. In this case, CDM of GrandParent would be triggered before CDM of any GrandChild
I could pass down a method from top to each GrandChild that would be called at CDM. On GrandParent I would wait for all GrandChild to call that method by using a counter and once the counter would be equal to the number of grandchildren I could call my piece of code that would scroll to the wanted grandchild, but this feels like a lot of hassle.
I want to load the GrandParent before the data comes down from the server, to render a placeholder/loading element.
I am looking for a more elegant method to solve this.
UPDATE:
Is componentDidMount of parent called after all componentDidMount of children?
I know why my GrandChildren's CDM is triggered after CDM of GrandParent just looking to have a different behaviour
In the end the most neat solution was the following:
I set up ComponentDidMount on IntermediateParent (works with IntermediateParent2 as well) which calls an action creator that sets a flag loadedX = true.
Then, in GrandParent's ComponentWillReceiveProps wait for the loadedX prop to become true. When this happens, manually call the desired 'callback' function. I inject the loadedX prop to GrandParent using connect.
Hope this also helps someone else. If you need more details ask in comments. I can also come up with some code for a more real world example.
We know that the children will render() when the parent render()s. This means we need to hook onto a parent render() and see if the children exist yet. We don't want to hook onto a child render() because that will run too many times and is kind of out of the scope of the child.
Looking at the React Component Lifecycle, we see that there are two ways to hook on after a parent render(), componentDidMount() and componentDidUpdate(). We know that we can't use componentDidMount() because the parent mounts before the children. However, we can use componentDidUpdate(). In your componentDidUpdate(), you can use refs, document.querySelector(), document.getElementById(), etc. to get a reference to the child. Once you are able to get the child reference, set a boolean flag so you only run the callback inside componentDidUpdate() once.
I feel like this is a cleaner solution. I think the accepted answer is kind of roundabout. You modify the IntermediateParent with ComponentDidMount(), actions using a dispatched redux action or a callback function in parent, and then the componentWillReceiveProps(). The componentWillReceiveProps() will also require a boolean flag like my solution.
Actually, maybe it isn't out of the scope of the child. Another solution is for the parent to pass a callback down to the child to call during the child's componentDidMount(). This callback will be called each time a child mounts, but you can keep a boolean flag in the parent so that the code only runs once.
I keep encountering the same problem with React. I feel I should be using the lifecycle methods. (Other than just componentWillMount and componentWillReceiveProps). But they never seem to meet my purpose. Here are 2 examples:
Asynchronous loading
My parent component loads some data with AJAX. A grandchild component needs this data - which is passed down via props. Because of the timing the data may be available when the child component is mounted or not. I don't know whether to put the code in my grandchild component which depends on these props in componentWillMount() or in componentWillReceiveProps(). I end up having to put it in both. (Or in a method they both call).
Lifecycle methods are either called on the initial render or not. I want them to be called on both.
My component gets some data. (Using getStateFromFlux - a mixin provided by Fluxxor). This occurs several times during the cycle of loading the data with various flags set onto the retrieved data object: unloaded, loading and loaded let's say. This change of state causes a re-render.
I only want to render and show the data if there is something to show. So - my render method has the first line:
if data.loadState != 'loaded'
return '<span />'
Ok. Well. I thought - there must be a lifecycle method to fix this. So I've done this:
shouldComponentUpdate: function (nextProps, nextState) {
if nextState.loadState == 'loaded'
return true
else
return false //stops the render. Good.
}
At last I thought - I have used a lifecycle method.
But, alas, while this does stop the render being called in some cases - when there is no data - I still can't remove the hacky looking line about
if data.loadState != 'loaded'
return '<span />'
This is because shouldComponentUpdate is not called for the initial render. When this component first renders there is no data. loadState is 'unloaded'. The render method is still called. And I still need to avoid displaying the UI (with empty data fields).
In general terms - the lifecyle methods are either called only on the initial render or only on subsequent renders. For most of my uses cases this is singularly unhelpful. I want a method which is agnostic to whether it is the first render or a subsequent one.
What am I missing about React? (The only thing I can think of is is that it is designed to be used with an initial render server-side when you can be sure of your data - then once in the browser the lifecycle methods are about detecting changes).
Thanks
Don't know about loading but with unloading I would suggest;
if (this.props.data.loadstate == 'unloaded') return null;
Have that as the first line of the render. As you noted shouldComponentUpdate only applies to updates.
You're right that you should be using the lifecycle methods, they're awesome and let you hook into your components in a much more in depth way. But I don't think this is the case for your current situation
You could just conditionally render the grandchild only when the data is loaded by the parent and passed to the child. Then you'd only need the check in the child. It would look something like this:
// Child render method that has been passed data loaded by the parent
render: function() {
var grandChild = null;
if (this.props.data) {
grandchild = <GrandChild data={this.props.data} />
}
return (
<div>
{grandchild}
</div>
)
}
In this case, you only pass a data prop to the child component once the data has loaded. Thus, you're guaranteed that when the grandchild component does render, it will have the data that it needs. Although I'm not sure why you are so averse to displaying empty data fields, this should solve the problem.
You're correct, there is no React lifecycle method that fires regardless of whether it's the initial render or not. That being said, if you have to do both, you can always a combination of componentDidMount and either componentDidUpdate or componentWillReceiveProps. I'm not 100% sure why they did this, but a couple reasons that come to mind:
Ensures that React will not need to re-render a component before the initial render (ie. changing state in componentWillReceiveProps, triggering an update before the initial render). I'm not too familiar with the code-base, but I can easily see that causing problems.
Performance boost for the initial render to let your content load faster while the virtual DOM is initialized
I hope this helps solve your problem and sheds some light on the lifecycle methods!
I have a YouTubeiFrame react component that renders an empty div and then drops the YouTube iframe player in to that div using componentDidMount. All works fine. I have a cueVideo method defined on the component which uses the players
API to cue new videos:
cueVideo(videoId) {
this.player.cueVideoById(videoId)
}
In different places in my app you can click a button or some another action to indicate that you want to play a new video. When you perform this action the 'currentVideo' state is updated via redux and as a result the YouTubeiFrame component receives the new video id as an updated prop.
My question is how to call the cueVideo method above in reaction to the updated prop. I've considered using shouldComponentUpdate to compare this.props.currentVideo with the next props
but concious this method is really supposed to return true/false so the render function can be called. All I want to do is call cueVideo when the currentVideo prop changes - I don't really need to re-render.
What's the best way to do this?
All I want to do is call cueVideo when the currentVideo prop changes - I don't really need to re-render.
When new props are received, React will automatically call render() to update your component. Once all the updates have been flushed to the DOM, React will also call componentDidUpdate() on your component to give you an opportunity to respond to the changes. As the documentation says:
Use this as an opportunity to operate on the DOM when the component has been updated.
I would suggest this is the perfect place to call your code as needed.