could you please tell me why my header render every time already use React.memo ? I have two section my app and user when I am navigation from my apps to user header re-render why ?
here is my code
https://codesandbox.io/s/fancy-microservice-gl734?file=/src/header.js
import React, { useEffect, useState } from "react";
import { withRouter } from "react-router-dom";
const Header = React.memo(function() {
console.log("HeaderHeaderHeaderHeaderHeader");
return <div>header</div>;
});
export default withRouter(Header);
when you run application it shows apps but when you are click user it show user page ..see console header is rerender
I tried with pure component still same issue
import React, { PureComponent } from "react";
class Header extends PureComponent {
render() {
console.log("HeaderHeaderHeaderHeader");
return <div>header</div>;
}
}
export default Header;
https://codesandbox.io/s/fancy-microservice-gl734?file=/src/test.js:0-202
Unfortunately, what you're trying to do is not how React works.
React.memo allows you to avoid running a child's render function if the parent component is rendering that child with the same props. If reconciliation replaces the parent with a new component, the new parent is not going to reuse the same memoized component even if it's rendering the same child as the last parent.
So in the case of your react-router, when you switch routes, every component will be re-rendered. The DOM may avoid unnecessary updates still, but your render functions will still get invoked.
If you pull the <Header/> component out higher up in the tree, you may be able to avoid your re-renders.
Related
This question concerns the definition of callback functions inside functional components, with the callback functions being passed down as props to child functional components.
I am aware that when defining functions inside functional components and those functions are being passed on as props to child components we should use useCallback. In this example I am deliberately not using it.
I have a dummy React app as below:
App.jsx
import { useState, useCallback } from 'react';
import './App.css';
import TestComponent from './components/TestComponent';
import TestComponent2 from './components/TestComponent2';
function App() {
const [message, setMessage] = useState("");
console.log('Defining myArrowfunc');
const myArrowFunc = () => console.log('Hello!');
console.log('myArrowfunc defined');
return (
<>
<TestComponent message={message} myArrowFunc={myArrowFunc} />
<TestComponent2 myArrowFunc={myArrowFunc} />
<input
type="text"
value={message}
onChange={e => setMessage(e.target.value)}
/>
<button
type="button"
onClick={() => {
console.log('Setting message');
setMessage("x");
}}>Set to x</button>
</>
);
}
export default App;
TestComponent.jsx
import { useEffect } from 'react';
function TestComponent(props) {
useEffect(() => {
console.log(`TestComponent.useEffect, props.message = ${props.message}`);
}, [props]);
return <h2>TestComponent - {props.message}</h2>;
}
export default TestComponent;
TestComponent2.jsx
import { useEffect } from 'react';
function TestComponent2(props) {
useEffect(() => {
console.log(`TestComponent2.useEffect`);
}, [props.myArrowFunc]);
return <h2>TestComponent2 - Placeholder</h2>;
}
export default TestComponent2;
Starting the app, the page loads and we are here:
In the console window everything looks like expected. The console.log statements Defining myArrowFunc and myArrowFunc defined ran, and we can see the console.log statements from the useEffect hook within TestComponent and TestComponent2 which ran after they were rendered.
Now we click on the button Set to x, which invokes the callback function attached to the onClick event of the button. This callback calls setMessage("x") which updates the state of the App component and consequently triggers a re-render of the component.
In the console window we can see that the App functional component ran (e.g. from the console.log("Defining myArrowFunc)) and one can also see that the useEffect hooks of the child components ran after they were re-rendered.
Now, that TestComponent re-rendered is of course understandable. message state is a prop on TestComponent which would cause a re-render of TestComponent. Also, in the dependency array of TestComponent is specified props (not props.message), but props is a new object on every render (right?) and hence the reference comparison tells us props has changed and so useEffect runs.
That the useEffect hook of TestComponent2 ran can be understood (right?) from the fact that myArrowFunc is re-defined on each render of App, and so the prop passed to TestComponent2 has in fact changed (reference comparison).
Here comes the part where I become confused: the message state in App now holds "x", and so additional clicks to the button will not change the state, and so should not trigger a re-render of App (and any child components dependant). When I click the button the following output happens:
The statements console.log('Defining myArrowfunc'); and console.log('myArrowfunc defined'); ran. What does this mean? Did the component re-render? If the App function ran, then it should have defined a new myArrowFunc (right?), and since TestComponent2 takes that as a prop, it should have re-rendered and run its useEffect hook?
What's interesting as well is that when I again click the button, it does not look like App ran, the output becomes only "Setting message".
Would very much appreciate an outline / explanation of what exactly is going on here.
When you click the button, a console log with setting message will run, and then a setState with will make a re-render.
At the following click, react is clever enough to see that the state you are setting is the same as before so it doesn't re-render
If you change then, the value and click the button, it will re-render, but not for the following cases with the same value.
To sum up, the first's console.log won't run if there's not a re-render, and the procedure of react--if default--memoizing will prevent it
I am new to react and I am trying to develop a simple web app with it but I get an error.
My Constructor is called twice when I load a class component can you help?
Home.js
import React from 'react'
import Land from "../Land";
function Home() {
return (
<div>
<h1>Home!</h1>
<Land/>
</div>
)
}
export default Home
Partial Land.js
import React, { Component } from 'react'
import Login from "./Login";
class Land extends Component {
constructor(props) {
super(props)
this.state = {
}
console.log("LAND")
}
the log LAND is hit twice.
In some of the components I wish to make an API call that hits a DB but I only want to hit it once.
In many instances using componentDidMount is not convenient because props only appear after componentDidMount therefor id like to do the call in render(I will not be using setState, that would cause a reload of render).
Thanks in advance
You are using <StrictMode/> and it's development mode
While in <StrictMode/>, react will detect unexpected side effects which will call lifecycle functions more than once duration the development mode, will not be trigger twice in production.
From docs:
why is called twice
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
will not call twice
Note:
This only applies to development mode. Lifecycles will not be double-invoked in production mode.
I didn't quite get what are you trying to say in the comment, but you totally can call function that fetches data within componentDidMount hook
Here's an example:
https://codesandbox.io/s/react-calls-constructor-twice-q5gzs
I'm trying to get some additional data from components and I don't know how. If it's possible, how can I get that and set it to a state?
It sounds like you're looking for props. The example from that documentation page is the Image component, which takes a source prop:
import React, { Component } from 'react';
import { AppRegistry, Image } from 'react-native';
export default class Bananas extends Component {
render() {
let pic = {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
};
return (
<Image source={pic} style={{width: 193, height: 110}}/>
);
}
}
// skip this line if using Create React Native App
AppRegistry.registerComponent('AwesomeProject', () => Bananas);
Your component receives props as the first argument to its constructor (if it's a class) or function (if it's a stateless functional component).
If it's possible, how can I get that and set it to a state?
You wouldn't usually do that. You might set state based on props (for instance: if you had a counter, you might have a prop for what number to start with and a state item for the current number), but usually you don't copy props to state directly. You can use props when rendering.
Probably a simple question with a simple answer, but I can't figure this out. Blame the heat. My simulator prints 'this is a test' on the screen, when I want it to say 'changed'. What am I doing wrong?
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Template from './src/components/Template';
export default class App extends React.Component {
constructor(props) {
super(props);
this.foo= "this is a test";
}
changeMe = () => {
this.foo = 'changed';
}
componentDidMount(){
this.changeMe();
}
render() {
return (
<Template foo={this.foo} />
);
}
}
Use state
You are using a class attribute witch will not trigger a re-render when changed. In react a component will re-render when it receives new props or when the state is changed (there's also a way to force it but best not to do that).
Example using the state to trigger a rerender
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Template from './src/components/Template';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state ={foo: "this is a test"};
}
changeMe = () => {
this.setState({foo:'changed'})
}
componentDidMount(){
this.changeMe();
}
render() {
return (
<Template foo={this.state.foo} />
);
}
}
When passing new props to a component it will also re-render (unless you implement componentShouldUpdate).
State explanation
So inside a react component you have a local state object in this.state it can be set in the constructor like this.state = {bar: 'foo'};. After the constructor has set the state it should only be changed with the this.setState() method.
Upon changing the state with setState the component will re-render with the updated values.
The state is not available outside of the component, at least not available as this.state because that would call the local state of the current component.
If you need to use a value from the state of a parent component you can pass it to a child. At that point it becomes a prop of the child accessible with
this.props
To change the value of state from a child component you should pass a function to the child that changes the state of the parent.
This process of passing state changing functions becomes increasingly complex as your app grows, I would suggest using a library like Redux to manage app state via actions and reducers. There is a steep learning curve but once you have a grasp of this modified flux methodology you will wonder how you ever lived without it.
I was trying to learn meteor and not very familiar with this pattern of HOC (it's meteor.js with react).
I was going though their offical docs of tutorials. Here is what they did (You can click here to visit the page)
They imported following package in App.js
import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import { Tasks } from '../api/tasks.js';
Then there is a simple to do class App extends component wrapped by this HOC
export default withTracker(() => {
return {
tasks: Tasks.find({}).fetch(),
};
})(App);
The official docs for the same says
The wrapped App component fetches tasks from the Tasks collection and
supplies them to the underlying App component it wraps as the tasks
prop. It does this in a reactive way, so that when the contents of the
database change, the App re-renders, as we'll soon see!
Now this language isn't exactly alien to me but I am having hard to comprehend and understand it. So Can someone explain me the same?
To be specific what is The wrapped App component fetches tasks and supplies it to underline app component
A higher order component is in the most basic form a function that takes a component type as input and returns a component class that wraps the input component and adds functionality to it.
Usually the signature is function that takes the argument to apply to the wrapped component which returns a HOC as described above so you can use it with multiple components.
Here is a very basic example that shows an error message if the component it's used on or any of it's child components throw an exception:
const catchError = ({ errorMessage }) => InputComponent => class extends Component {
render() {
try {
return <InputComponent {...this.props} />;
} catch {
return <div>{errorMessage}</div>
}
}
}
const ComponentWithErrorMessage = catchError({ errorMessage: 'Whoops!' })(MyComponent);
// This is the same as the following, the first just immediately invokes the returned function
const whoopsErrorHoc = catchError({ errorMessage: 'Whoops!' });
const ComponentWithWhoopsError = whoopsErrorHoc(MyComponent);
The meteor HOC will be a bit more complicated but the idea is the same. It receives a reference to the meteor Task store and will return a component that re-renders the input component whenever the data changes in the store and add the data to the props of that component.