I have a parent component which is a flat list which contains a header HeaderComponent. This HeaderComponent is a custom component that I have created which contains 2 child components of its own. Whenever i refresh the list, I am passing a boolean to the HeaderComponent as props which get passed onto its own children, I am doing this so I can check if each component needs to fetch new data or not. The problem is that whenever the parent refreshes and sets a new state the constructors of the child components get called everytime. Shouldn't the constructor be called only the first time the parent initializes and then all further calls involve calling the shouldComponentUpdate method of the children in order to see if it needs an update or not.
Parent component
_renderHeader = () => {
return <HeaderComponent Items={this.state.Data} refresh={this.state.refresh}/>;
};
render() {
console.log("TAG_RENDER render called " + this.state.refresh);
return (
<FlatList
refreshing={this.state.refresh}
onRefresh={() => {
console.log("onRefresh");
this.setState({
refresh: true
}, () => {
this._fetchData();
});
}}
......
ListHeaderComponent={() => this._renderHeader()}
.......
/>
);
}
Header Component
export default class HeaderComponent extends React.Component {
constructor(props) {
super(props);
console.debug("HeaderComponent");
}
render() {
return (
<MainHeader Items={this.props.Items}/>
<SubHeader refresh={this.props.refresh}/>
);
}
}
The constructor of MainHeader and Subheader gets called whenever the parent component refreshes. Does this mean that it is creating new child components each time it refreshes because I can see the render of the children also being called multiple times.
Control your index.js file. If you see <React.StrictMode>, you should change to <>. This is solved my problem.
It should be like:
ReactDOM.render(
<>
<App/>
</>,
document.getElementById('root')
);
As correctly stated in the one of the answers , removing the strict mode fixes the issue. Coming to why it does that, its because the strict mode intentionally calls the 'render' method twice in order to detect potential problems.
React works in two phases:render and commit. Render phase checks and determines the new changes to be applied. And commit phase applies it.
Render phase lifecycle includes methods like : constructor, UNSAFE_componentWillMount,UNSAFE_componentWillReceiveProps, ...,render and few more.
The render phase is time consuming and is often broken into pieces to free up the browser. Render phase might be called multiple times before the commit phase(usually very fast).
Since the render phase methods are called more than once, its important that none of those method have any problems or side effects.
Thus just in order to highlight the possible side effects to make them easy to spot, react explicitly double invoke the render phase methods.
You can read more about this on :https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects :)
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate
methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer
https://reactjs.org/docs/strict-mode.html
As stated in the site,
Note:
This only applies to development mode. Lifecycles will not be double-invoked in production mode.
Related
I read in an article that if you have some code like:
class Parent extends Component {
render() {
return (
<Child
onClick={() => console.log('You clicked!')}
/>
);
}
}
Child will be re-rendered every time Parent re-renders, even if there's no change in its props, only because the onClick function is inline and so it creates a new reference on every render.
However, even after moving that function outside of render(), Child re-rendered.. so what am i missing here?
In addition, that article also mentioned that inline functions increases a React app's memory footprint, since a new function reference is created on each render. Is that true? Doesn't JS have some sort of automatic garbage collection?
A couple of things, what you have posted only works for Class components, and as to why it works with Class components is that you are creating a callback function and binding it to the instance of the component, therefore each render of the component, it is the same callback function instance being used.
More reading on this https://www.freecodecamp.org/news/this-is-why-we-need-to-bind-event-handlers-in-class-components-in-react-f7ea1a6f93eb/ under "Why don’t we need to bind ‘this’ for Arrow functions?"
For a function component, it's different, there is no class instance, you can use the useCallback hook that will memoize a callback, given a set of dependencies remain the same.
As someone pointed out in the comments you should only really aim to memoize callbacks etc though when they will prevent rerenders of large/deep children
I was facing multiple re-renders and thus to find the issue I commented every line of code and at last found the constant definition causing re-render:
const MyComponent = () => {
console.log('render') // logs 4 times
const myRef = useRef(null)
return <h1>hello</h1>
}
const MyComponent = () => {
console.log('render') // logs 2 times
return <h1>hello</h1>
}
I know strict mode renders the component 2 times. But, why just defining myRef constant causing re-render further 2 times?
I just tried React.memo as comment, but it still renders 4 times:
export default React.memo(MyComponent)
Okay, I just tested using the same code in App.js and it only logged 2 times. So, it seems to be parent component issue. But my question is why in the child component without having anything causing renders additional 2 times just defining the variable?
As you and React docs said:
Strict mode can’t automatically detect side effects for you, but it
can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer
Source: https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects
It does not include useRef but it actually should be on this list because it uses same underlying mechanism as useState
React.memo won't help here because what causes re-render is React.StrictMode special mechanism to check side effects and other stuff, so it ignores memo and similar techniques.
What's interesting here that if you add useRef in Parent component it will invoke function body 2 times, but its children (if they don't use useRef) are gonna be invoked only once.
All this stuff only works for development mode, so in production there won't be any intentional double invocations and other things but they can still happen unintentionally.
i am setting the language name in my local storage , when it changes from a dropdown in topbar , i want the whole current view to be re-rendered and words translated to the selected language. my layout is like this
render(){
return (
<MainContainer>
<TopBar/>
<SideBar/>
<RouteInsideSwitch/>
</MainContainer>
)
}
in render of components ,the words to be translated basically calls a function that returns the correct word based on the local storage language name.
i change the language and i set the state in maincontainer for selected langauge and set it in local storage. however i dont want to move that state from Maincontainer to all my components. also dont want to store it in redux because then all the possible containers have to listen to it and then pass it to their children as props.
what currently happens is that saving state in mainContainer without passing it to any children , the children does re-render but only the immediate ones , if there are more children in those children and so on , it does not re-render because i m not passing the state throughout the chain.
open to any suggestion based on different pattern for language changing. but my question is that is there any way to re-render the current open view (all components in dom).
If your concern is that you have a number of "possible containers" which all need to handle the state change, perhaps consider creating a higher order component that includes the common language rendering logic (your RouteInsideSwitch leads me to believe this may the issue). In that way, you can avoid duplicating that logic across a ton of "possible" components that all require the functionality of dynamic language rendering and will avoid the need to dial a bunch of components into a redux store, assuming they are in the same hierarchy.
const DynamicLanguageComp = RenderComponent => {
return class extends Component {
constructor(props) {
super(props)
//additional state setup if needed
}
changeLangFunc = () => { /* handle change */ }
render() {
return <RenderComponent handleLanguageChange={this.changeLangFunc} {...this.props} {...this.state} />
}
}
}
If you would like to avoid a re-render on certain intermediate components that may be receiving props by way of state change you can implement the lifecycle method shouldComponentUpdate(), which by default returns true. You can make a comparison of nextProps to your current props, and return false if a re-render is undesired despite new props.
I'm learning React. It seems to me that HOC like the following example from React's official docs:
function withSubscription(WrappedComponent, selectData) {
// ...and returns another component...
return class extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props)
};
}
componentDidMount() {
// ... that takes care of the subscription...
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
// ... and renders the wrapped component with the fresh data!
// Notice that we pass through any additional props
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}
can be rewritten in this way:
class WithSubscription extends React.Component {
constructor({ component, selectData, ...props }) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props)
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
return <component data={this.state.data} {...this.props} />;
}
}
Then use it like this:
<WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />
Are they both HOC? When is one style preferred than the other?
I was struggling with HOC too at first. Another way of looking at this is at wrappers of components that you could use to isolate the functionality from one component.
For example, I have multiple HOC. I have many components that are only defined by props, and they are immutable once they are created.
Then I have a Loader HOC Component, which handles all the network connectivity and then just passes the props to whatever component is wrapping (This would be the component you pass to the HOC).
The loader does not really care which component it is rendering, it only needs to fetch data, and pass it to the wrapped component.
In your example, you can actually accomplish the same, however it will become much more complex once you need to chain multiple HOC.
For example I have this chain of HOCs:
PermissionsHOC -> LoaderHOC -> BorderLayoutHOC -> Component
First one can check your permissions, second one is loading the data, third one is giving a generic layout and the forth one is the actual component.
It is much easier to detect HOCs if you realize that some components would benefit from having a generic logic on the parent. You could do the same in your example, however you would need to modify the HOC every time you add a child component, to add the logic for that one. Not very effective. This way, you can add new components easily. I do have a Base component which every component extends, but I use it to handle the helper functions like analytics, logger, handling errors, etc.
What they call an "HOC" is basically a function (just a regular function, not React specific) that behaves like component factory. Meaning it outputs wrapped components that are the result of wrapping any inside-component of your choice. And your choice is specified with the "WrappedComponent" parameter. (Notice how their so-called "HOC" actually returns a class).
So I don't know why they called it an "HOC" tbh. It's just a function that spits out components. If anyone knows why I'd be interested in hearing the reason.
In essence their example is doing exactly what you're doing, but it's more flexible because WrappedComponent is being taken in as a parameter. So you can specify whatever you want. Your code, on the other hand, has your inside component hard coded into it.
To see the power of their example, let's say you have a file called insideComp.js containing:
import withSubscription from './withSubscription';
class InsideComp extends React.Component{
// define it
}
export default withSubscription(InsideComp);
And when you use insideComp in another file:
import myComp from './insideComp.js';
You're not actually importing insideComp, but rather the wrapped version that "withSubscription" had already spit out. Because remember your last line of insideComp.js is
export default withSubscription(InsideComp);
So your InsideComp was modified before it was exported
The second one is not a HOC.
They coin the word HOC from higher order functions. One example of a higher order function is a function that takes a function as an argument and returns another function.
Similarly, a HOC is a function that takes an component as argument and returns another component.
This does sound weird to me because a higher order component is not a react component; it is a function instead. I guess the reason they call it HOC is because:
A react component is a class, which is indeed a constructor function in JavaScript (except that functional components are simply functions). A HOC actually takes a function (a constructor function) and returns another function (another constructor function), so it is actually a higher order function if you think about it. Probably because it is in the react context and this is a pattern to transform components, they call it HOC.
As to the difference between the two styles you mentioned:
First one: you would use the first one to generate a class like MyComponnet = withSubscription(AnotherComponent, ...), and whenever you need it in a render call just write <MyComponent><MyComponent>
Second one: this is less common. Every time you need it in a render call, you would need to include the WithSubscription component as you mentioned in the description <WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />
We have a crazy DOM hierarchy, and we've been passing JSX in props rather than embedding children. We want the base class to manage which documents of children are shown, and which children are docked or affixed to the top of their associated document's window.
List (crazy physics writes inline styles to base class wrappers)
Custom Form (passes rows of JSX to Base class)
Base Class (connects to list)
Custom Form (passes rows of JSX to base class)
Base class (connects to list)
The problem is that we're passing deeply nested JSX, and state management / accessing refs in the form is a nightmare.
I don't want to re-declare every row each time, because those rows have additional state attached to them in the Base Class, and the Base Class needs to know which rows actually changed. This is pretty easy if I don't redeclare the rows.
I don't know how to actually deal with rows of JSX in Custom Form.
Refs can only be appended in a subroutine of render(). What if CustomForm wants to measure a JSX element or write inline CSS? How could that JSX element exist in CustomForm.state, but also have a ref? I could cloneElement and keep a virtual DOM (with refs) inside of CustomForm, or depend on the base class to feed the deeply-nested, mounted ref back.
I believe it's bad practice to write component state from existing state. If CustomForm state changes, and I want to change which rows are passed to BaseClass, I have to throttle with shouldComponentUpdate, re-declare that stage document (maintaining row object references), then call setState on the overarching collection. this.state.stages.content[3].jsx is the only thing that changed, but I have to iterate through every row in every stage document in BaseClass when it sees that props.stages changed.
Is there some trick to dealing with collections of JSX? Am I doing something wrong? This all seems overly-complicated, and I would rather not worsen the problem by following some anti-pattern.
Custom Form:
render () {
return <BaseClass stages={this.stages()}/>
}
stages () {
if (!this._stages) this._stages = { title: this.title(), content: this.content() };
return this._stages;
}
title () {
return [{
canBeDocked: false,
jsx: (
<div>A title document row</div>
)
}
}
content () {
return [{
canBeDocked: false,
jsx: (
<div>Hello World</div>
)
}, {
canBeDocked: true,
jsx: (
<div>Yay</div>
)
}
}
What I usually do is just connect the lower level components via Redux. This helps with not passing the state in huge chunks from the top-most component.
A great video course by one of the React creators, Dan Abramov: Getting started with Redux
Absolutely agree with #t1gor. The answer for us was to use REDUX. It changed the entire game for us. Suddenly a button that is nested 10 levels deep (that is, inside a main view, header, header-container, left side grid, etc, etc, deeper and deeper) into purely custom components, has a chance to grab state whenever it needs.
Instead of...
Parent (pass down state) - owns state vars
Child (will pass down again) - parent has state vars
Grandchild (will pass down a third time) - grandparent has state vars
Great Grandchild (needs that state var) - great grandparent has state vars
You can do...
Parent (no passing) - reads global state vars
Child
Grandchild
Great Grandchild - also reads same global level state vars without being passed...
Usually the code looks something like this...
'use strict'
//Importation of Connection Tools & View
import { connect } from 'react-redux';
import AppView from './AppView';
//Mapping -----------------------------------
const mapStateToProps = state => {
return {
someStateVar: state.something.capturedInState,
};
}
const mapDispatchToProps = dispatch => {
return {
customFunctionsYouCreate: () => {
//do something!
//In your view component, access this by calling this.props.customFunctionsYouCreate
},
};
}
//Send Mappings to View...
export default connect(mapStateToProps, mapDispatchToProps)(AppView);
Long story short, you can keep all global app state level items in something called a store and whenever even the tiniest component needs something from app state, it can get it as the view is being built instead of passing.
The issue is having content as follows, and for some reason not being able to effectively persist the child instances that haven't changed (without re-writing the entire templateForChild).
constructor (props) {
super(props);
// --- can't include refs --->
// --- not subroutine of render --->
this.state = {
templateForChild: [
<SomeComponentInstance className='hello' />,
<AnotherComponentInstance className='world' />,
],
};
}
componentDidMount () {
this.setState({
templateForChild: [ <div className='sometimes' /> ],
}); // no refs for additional managing in this class
}
render () {
return ( <OtherManagerComponent content={this.state.templateForChild} /> );
}
I believe the answer could be to include a ref callback function, rather than a string, as mentioned by Dan Abramov, though I'm not yet sure if React does still throw a warning. This would ensure that both CustomForm and BaseClass are assigned the same ref instance (when props.ref callback is executed)
The answer is to probably use a key or createFragment. An unrelated article that addresses a re-mounting problem. Not sure if the fragment still includes the same instances, but the article does read that way. This is likely a purpose of key, as opposed to ref, which is for finding a DOM node (albeit findDOMNode(ref) if !(ref instanceof HTMLElement).