What renders a function in React - reactjs

I have following component:
const RenderJobsTable = props => {some render stuff in here};
And I call that function in another functions render:
<Collapse isOpen={toggleJobTable} id="collapseExample">
<CardBody>
<RenderJobsTable
crawl={props.crawl}
jobs={jobs}
></RenderJobsTable>
</CardBody>
</Collapse>
I noticed that every time I collapse the outer element and toggle it so it gets visible again, the function is called again. What exactly triggers the function to be called in React? Is it when the element is visible? Is if if one of it's parameters changes? Or if parent functions gets changed? If I just toggle the element and I have some call's to a rest service I don't want that to happen all the time. So I need to understand what triggers the call.

Basically, Reacts render method gets triggered almost every time something related to the state of the component changes. From How does React decide when to re render a component?:
A re-render can only be triggered if a component’s state has changed. The state can change from a props change, or from a direct setState change. The component gets the updated state and React decides if it should re-render the component. Unfortunately, by default React is incredibly simplistic and basically re-renders everything all the time.
Component changed? Re-render. Parent changed? Re-render. Section of props that doesn't actually impact the view changed? Re-render.
You can also refer to a similar question's answer.
Related to when to make API calls, I strongly suggest that you read about React component Lifecycle (for example here or here).
TLDR, place your API calls in componentDidMount().

Related

Will componentDidUpdate fire everytime for a component that renders null?

Will componentDidUpdate always fire for a component that renders empty fragment/null ? It receives redux connected props from the parent container.
This component needs to access previous props and compare, then make an API call based on it. It doesn't have UI, so it renders empty fragment (or null)
EDIT : It is working and firing componentDidUpdate in my sample application. Is this guaranteed to be the behavior always?
It says here that there is a chance it may not fire when there was no change in the virtual DOM: Props updated, componentDidUpdate did not fire
MyContainer
|
-MyComponent
Yes it run every time instead at time of first initial render
Yes componentDidUpdate is called every time, even when rendering null. You can check this in the react documentation: React Lifecycle

Will componentWillMount run again if component is re-rendered because of parent component?

Will componentWillMount run again if component is re-rendered because of parent component?
No, componentWillMount is called only once.
Also, componentDidMount is called only once.
componentDidUpdate is called on every re-render.
To correctly understand about the react lifecycle methods you can go through this link.
https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1
The short answer is NO
It's called once right before your component is about to be rendered to the DOM.
The long answer is:
componentWillMount
Your component is going to appear on the screen very shortly. That chunky render function, with all its beautifully off-putting JSX, is about to be called.
Most Common Use Case: App configuration in your root component.
Can call setState: Yes, but don't. Use the default state instead.
componentDidMount
Here is where you load in your data. ComponentDidMount is also where you can do all the fun things you couldn’t do when there was no component to play with. Basically, here you want to do all the setup you couldn’t do without a DOM, and start getting all the data you need. Most Common Use Case: Starting AJAX calls to load in data for your component.
componentWillReceiveProps
Perhaps some data that was loaded in by a parent component’s componentDidMount finally arrived and is being passed down. Before our component does anything with the new props, componentWillReceiveProps is called, with the next props as the argument.
shouldComponentUpdate
shouldComponentUpdate should always return a boolean — an answer to the question, “should I re-render?” Yes, little component, you should. The default is that it always returns true. It's an awesome place to improve performance.
componentWillUpdate
Most Common Use Case: Used instead of componentWillReceiveProps on a component that also has shouldComponentUpdate (but no access to previous props). It’s basically the same as componentWillReceiveProps, except you are not allowed to call this.setState.
componentDidUpdate
Here we can do the same stuff we did in componentDidMount — reset our masonry layout, redraw our canvas, etc. Basically, we use it when it's all said and done, but we don’t want to waste time to redraw the canvas every time it updates. Most Common Use Case: Updating the DOM in response to prop or state changes.
componentWillUnmount
Here you can cancel any outgoing network requests, or remove all event listeners associated with the component. Basically, clean up anything to do that solely involves the component in question — when it’s gone, it should be completely gone.

componentDidUpdate called twice every route change

In my application i have a HomePage component which has navlinks in it. the route for this component is <Route to="/browse/:item" exact component={HomePage} />. so the component has a navigation bar with NavLink links to "sub routes" of it. for example a NavLink that leads you to /browse/featured or
/browse/new and i added to this component the lifecycle method componentDidUpdate() to just console.log("UPDATED HOMEPAGE") and whenever i click a NavLink this happens:
i tried to use shouldComponentUpdate with the nextProps and nextState params to see if indeed the state or props are changed (something that will cause a re-render) but they stay the same.
Thanks in advance for your help.
EDIT:
the code is on github https://github.com/idanlo/spotify-test-frontend
components that have the problem that i have seen are AlbumView and HomePage
ANOTHER EDIT:
this is a console.log() of the two updates happening, each one displaying the props before and after the update. on the first update you can see that the url is different so the update is supposed to happen but on the second update nothing is different, everything is the same (in the state everything is the same too)
Usually there are multiple calls because of changes made to the state. Check other files to make sure that no actions that modify the state are initially called. Even though you check for differences for nextProps, the variable that changes might not be in props.
I suspect that Navlink's internal implementation uses setState with an updater function which is the source of this duplicate log
I found that when I update state with an updater function then componentDidUpdate gets fired twice!
However when I pass an object to setState - componentDidUpdate is fired only once.
setState(updater[, callback])
example:
incrementScore = () => {
this.setState(prevState => ({
score: prevState.score + 1
}));
};
VS
setState(stateChange[, callback])
example:
this.setState({quantity: 2})
I guess it's because
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
read about setState on React Docs

Weird component lifecycle with react router

I have this route (simplified)
<Route
path="/foo/:id">
render={({match}) => (
<Page key={match.params.id} id={match.params.id}/>
)}
</Route>
Now the reason for that is that when I go from /foo/1 to /foo/2 I don't want to clear and update state of an existing component, it's too complex in my case. So I have a dynamic key which causes to unmount the /foo/1 component and mount a brand new /foo/2 component.
So far so good. But here is the catch. The lifecycle I observed is this
/foo/1 re-render
/foo/2 constructor
/foo/2 componentDidMount
/foo/1 componentWillUnmount
/foo/2 render
Why doesn't the first component unmount before the second one mounts? Because of that I get weird re-renders and glitches (it's connected to redux store and initialization of the /foo/2 component changes the store which manages to re-render still existing component /foo/1). Any ideas how to avoid this?
Thanks
It is hard to determine exactly what is happening with your short snippet of code, but, I believe your issues are relating to some anti-patterns;
A react component constructor should only be used for two things:
Initialising local state
Binding event handlers
https://reactjs.org/docs/react-component.html#constructor
Secondly you are using the render prop with a inline function, this means when ever a matching route is detected and the parent component re-renders it will re-construct the component, un-mounting it first then mounting it again. To prevent this you should be defining the render function outside of the parents render function.
Thirdly because you have a dynamic route /foo/:id and assigning the value of :id to the key of the child component react sees it as a different component and doesn't unmount it until the current render process has reached the un-mounting stage. This means that for a short period of time you have <Page key={1} /> & <Page key={2}/> present.
Because these three issues, you are getting what seems to be a weird component lifecycle but in fact it is react doing exactly what you told it to do.
The Solution:
Move the redux action being invoked in the constructor of the <Page /> to be in the componentDidMount() function.
Move the inline render function to be outside the parent render function.
Remove the key prop.

Call custom method on component when props update

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.

Resources