I am using react 16.13.1 and created react app using create-react-app 3.4.1.
Mounting lifecycle is being called twice for every component.
I created component FirstComponent.js
import React, {Component} from 'react';
class FirstComponent extends Component {
constructor(p) {
super(p);
console.log("FirstComponent constructor called")
}
componentDidMount() {
console.log("FirstComponent componentDidMount called")
}
static getDerivedStateFromProps() {
console.log("FirstComponent getDerivedStateFromProps called")
return null;
}
render() {
console.log("FirstComponent render called")
return (
<div>
Hello World
</div>
);
}
}
export default FirstComponent;
and called FirstComponent from App.js
import React, {useEffect} from 'react';
import FirstComponent from "./FirstComponent";
function App() {
useEffect(()=>console.log("App useEffect Called"));
console.log("App called");
return (
<FirstComponent/>
);
}
export default App;
console output: (ignoring getDerivedStateFromProps warning)
App called
App called
FirstComponent constructor called
FirstComponent constructor called
FirstComponent getDerivedStateFromProps called
FirstComponent getDerivedStateFromProps called
FirstComponent render called
FirstComponent render called
FirstComponent componentDidMount called
App useEffect Called
This is because codesandbox.io runs react applications in strict mode by using <React.StrictMode /> and in strict mode side effects are double-invoked means executed two times, if you unwrap your <App /> component from <React.StrictMode> in index.js it'll work just fine.
Here's how docs define this:
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
Related
I have recently started to use React for specific parts of my custom JavaScript application. It is going well, but I don't quite understand how I can "unmount" or "stop rendering" or "clean up" a React component when I no longer need it?
Consider the following example of opening a modal that is a React component. How do I then close it and clean up the React side of things properly?
MyApp.js (JavaScript only, no React)
import { renderReactModal } from "./ReactModal.jsx";
class MyApp {
// I call this when I want to show my React component
openReactModal() {
// Create an empty div and append it to the DOM
this.modalDomElem = document.createElement("div");
document.append(this.modalDomElem);
// Render the React component into the div
renderReactModal(this.modalDomElem);
}
// I call this method when I want to hide my React component
closeReactModal() {
// Is it enough to do this to unmount / stop the React component from rendering?
// Or is there any other React-specific clean-up code required?
this.modalDomElem.remove();
}
}
ReactModal.jsx (React goes here)
import React from "react";
import ReactDOM from "react-dom";
class ReactModal extends React.Component {
render() {
return <h2>React Modal</h2>
}
}
export const renderReactModal = (domElem) => {
// NB: This syntax is for React 16 (different in 18).
ReactDOM.render(
<ReactModal />,
domElem
);
}
I searched some more and eventually found my way to this section of the React Docs: https://reactjs.org/docs/react-dom.html#unmountcomponentatnode
It seems that using ReactDOM.unmountComponentAtNode(container) is the recommended way to achieve this:
Remove a mounted React component from the DOM and clean up its event handlers and state.
Using that idea, I can change my initial code as follows.
MyApp.js (JavaScript only, no React)
import { mountReactModal, unmountReactModal } from "./ReactModal.jsx";
class MyApp {
// I call this method when I want to show my React component
openReactModal() {
// Create an empty div and append it to the DOM
this.modalDomElem = document.createElement("div");
document.append(this.modalDomElem);
// Mount the React component into the div
// NB: This causes the React component to render
mountReactModal(this.modalDomElem);
}
// I call this method when I want to hide my React component
closeReactModal() {
// Unmount the React component from the div
// NB: This cleans up the React component's event handlers and state
unmountReactModal(this.modalDomElement);
// Remove the div from the DOM
this.modalDomElem.remove();
}
}
ReactModal.jsx (React goes here)
import React from "react";
import ReactDOM from "react-dom";
class ReactModal extends React.Component {
render() {
return <h2>React Modal</h2>
}
}
// Mount
export const mountReactModal = (domElem) => {
// NB: This syntax is for React 16 (different in 18).
ReactDOM.render(
<ReactModal />,
domElem
);
}
// Unmount
export const unmountReactModal = (domElem) => {
// NB: This syntax is for React 16 (different in 18).
ReactDOM.unmountComponentAtNode(domElem);
}
In my mental model, React function components are basically class components stripped down to render method (and this is reinforced by React docs saying that that render should be a pure function of state and props). I assume that render method and Functional components are called at the same phase of React lifecycle so why I can't use hooks in render method? To be more precise, I want to know the technical limitations of class components which disallow hooks usage.
import React from "react";
export default class App extends React.Component {
render() {
const [state, setState] = React.useState(0); // Invalid hook call. Hooks can only be called inside of the body of a function component.
return (
<div>
<h1>Hello World</h1>
</div>
);
}
}
no, we can't use hooks with class component. So, please, read the documentation
Rules of hooks:
✅ Call Hooks from React function components.
✅ Call Hooks from custom Hooks (we’ll learn about them on the next page).
I have a most basic React PureComponent, wrapped with withRouter:
import React from 'react';
import {withRouter} from "react-router-dom";
import { shallowEqualExplain } from 'shallow-equal-explain';
class TestComp extends React.PureComponent{
componentDidUpdate(prevProps, prevState){
const shallowEqualExplanation = shallowEqualExplain(
prevProps,
this.props,
);
console.log("TEST COMP DID UPDATE", shallowEqualExplanation);
}
render(){
return(
<div>
</div>
)
}
}
export default withRouter(TestComp);
The component re-renders every time the parent is updated, even though no prop is passed down from the parent.
Using shallow equal explain tells me that the match property sent by withRouter is changed even though my path is exactly the same.
Any idea how to fix that?
(I do not wish to use shouldComponentUpdate as it might work in this very simple example but is tedious to implement in all the components of my application)
I have a functional Component which is using the hook useCallback. For the last few days everything was just fine. All worked as it should. Today I start up the app and I have this error:
React Hook "useCallback" is called in function "loginPage" which is neither a React function component or a custom React Hook function
This makes no sense because it has been fine. For debugging I simply erased all code on the page except that one coed and even just put a useCallback template in its place, but still the same. It is as if it has been removed from react entirely.
I checked my react version and find 16.8.6 also in react-dom.
Does anyone have any ideas?
import React, {Fragment,useCallback } from 'react';
import { Redirect} from 'react-router-dom';
import {useDropzone} from 'react-dropzone';
const loginPage = (props) => {
const callbackFunction = useCallback(() => {
console.log("callback called");
// Do something with callbackCount ...
return true;
}, []);
}
I see three problems why the error occurred.
which is neither a React function component or a custom React Hook function
loginPage is not a component. useCallback is a hook and it needs to be called inside a function component (not a class component) or in another hook (a function whose name starts with "use"). Check out the rules of hooks.
And also the component name should start with a capital letter, so it should be LoginPage for it to be a valid React component.
You are not returning anything from your component.
I am writing a stateless function component in React using WebStorm:
// file1.js
import React from "react";
export default function MyComp({foo}) { return <span>{ foo }</span>; }
Later, I reference the component:
import MyComp from "./file1";
// ... in my other component ...
// I am definitely using the component:
render() { return <MyComp foo="bar"/> }
When performing code analysis, WebStorm complains with the following warning:
Warning:(6, 25) Unused function MyComp
Is this a bug in WebStorm? Do I need to configure WebStorm for React?
Thanks.