ReatctJS ComponentDidUpdate not firing? - javascript

Simple example but not sure why I can't get it to work:
class Grid extends React.Component {
componentDidUpdate = () =>{
alert('Should Fire')
}
render() {
return (<div>{this.props.name}</div>)
}
}
class Application extends React.Component {
render() {
return (<div><Grid name="test-grid" /></div>);
}
}
The componentDidUpdate method does not fire in the Grid class. Insight?

Instead you can use componentDidMount(). You are not updating the props which should trigger update event. See from the documentation of componentDidUpdate():
componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render.
As the following:
class Grid extends React.Component {
componentDidMount = () =>{
alert('Should Fire')
}
render() {
return (<div>{this.props.name}</div>)
}
}
I hope this helps!

componentDidUpdate function only fires when the parent component re-renders causing the child to re-render.
In your case the parent isn't re-rendering at all. Its just the initial render.
To detect an initial render, you would make use of componentDidMount function. You can see the componentDidUpdate function being fired if you have a state in parent that you update based on an interaction or any other way
class Grid extends React.Component {
componentDidMount(){
alert('Should Fire')
}
componentDidUpdate() {
alert('ComponentDidUpdate Should Fire');
}
render() {
return (<div>{this.props.name}</div>)
}
}
class Application extends React.Component {
state = {
count: 0
}
render() {
return (
<div>
<Grid name="test-grid" />
<button onClick={()=>this.setState(prev => ({count: prev.count + 1}))}> increment</button>
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"/>

Related

React - passing 'this' as a prop

Is there any side effect I do not see by doing this ?
class App extends React.Component {
hello() {
console.log("hello")
}
render() {
return <Layout app={this}>
}
}
So later on I can refer to this.props.app.hello (and others) from Layout ?
This is not safe.
React will not know how to watch for changes, so you may miss re-renders. React uses === to check for state changes, and App will always be === to App, even when state or properties change.
Take this example:
class App extends React.Component {
constructor(props) {
super(props);
this.setState({text: 'default value'});
}
hello() {
this.setState({...this.state, text: 'new value'});
}
render() {
return (
<div onClick={this.hello}>
<Layout app={this}>
</div>
);
}
}
class Layout extends React.Component {
render() {
return <div>{this.app.state.text}</div>
}
}
When you click on the parent div, this.hello will be called, but the child component will not detect the state update, and may not re-render as expected. If it does re-render, it will be because the parent did. Relying on this will cause future bugs.
A safer pattern is to pass only what is needed into props:
class App extends React.Component {
//...
render() {
return (
<div onClick={this.hello}>
<Layout text={this.state.text}>
</div>
);
}
}
class Layout extends React.Component {
render() {
return <div>{this.props.text}</div>
}
}
This will update as expected.
Answer
There's nothing wrong in passing functions as props, as I can see in your example, the only thing you have to do is make sure your function is bound to the current component like the following example
Reference
React: Passing Functions to Components

Functional component definition inside class component's render() method, state resets when created through JSX, but not when called directly

If I define a functional component inside of a class component's render() method, then the component's state is getting reset every time the class component's render() method is called. If I call the functional component directly though, the state does not reset.
Look at the following example:
import React from 'react';
import Counter from './Counter'
const MilliCounter = ({name}) => {
return <Counter name={name} initial={1e6} />
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
flag: false
}
}
onButtonClick = (event) => {
this.setState({flag: !this.state.flag});
};
render() {
const HundoCounter = ({name}) => {
return <Counter name={name} initial={100} />
};
return (<div>
<button onClick={this.onButtonClick}>Change State</button>
<div>{`Flag: ${this.state.flag}`}</div>
<HundoCounter name="Component Def Inside render() - Hundo JSX"/>
{HundoCounter({name: 'Component Def Inside render() - Hundo Function Call'})}
<MilliCounter name="Component Def Outside render() - Milli JSX"/>
{MilliCounter({name: 'Component Def Outside render() - Milli Function Call'})}
</div>)
}
}
export default App;
import * as React from 'react'
export default class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: props.initial
}
}
onButtonClick = (event) => {
this.setState({
count: this.state.count + 1
})
};
render() {
return (
<div style={{border: '1px solid black', margin: '1rem', padding: '0.67rem'}}>
<h6>{this.props.name}</h6>
<p>Count: {this.state.count}</p>
<button onClick={this.onButtonClick}>Click Me</button>
</div>
)
}
}
Here's a video showing the demo app in action.
https://i.imgur.com/WfS8DXJ.mp4
As you can see, when the button is clicked it changes the flag to true which forces a re-render. During this the state of the functional component HundoCounter defined with JSX is reset, but not the one that is called directly.
It makes sense to me that the state would reset, because it's creating a new definition of HundoCounter every time render() is called. How come the state for the HundoCounter that's called directly as a function does not get reset?
I believe the reason is because you're re-rendering the parent component, which then resets the initial={100} to set it back to 100, when the child component is re-rendered due to the parent re-render.
Which is the intended behaviour
As for why the second one isn't resetting i don't know, but it seems odd that it is not, since it's value should also be reset
Okay it seems odd. I think it is related with React's reconciliation and diff algorithm. When I add the key property to Counter component it behaves what we expect.
const HundoCounter = ({ name }) => {
console.log("hundo function")
return <Counter key={Math.random()} name={name} initial={100} />
};
I think render() method is called and the diff algorithm recurses on the previous result and the new result and somehow function surround the component and behaves like it is the same component. Btw I like this experiment :)

Parent state undefined in componentDidMount event of the child component

I'm setting the state of my parent component in componentDidMount and passing its value to a child component via props, but even though the input is filled, when I run console.log(this.props.value) in the componentDidMount event of the child component, it is undefined. I need this value updated in this event.
How to get the correct prop value in this scenario?
Example code:
class Text extends React.Component {
componentDidMount(){
console.log(this.props.value);
}
render() {
return (
<div>
<input type="text" value={this.props.value} />
</div>
);
}
}
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {}
};
}
componentDidMount(){
let data = {
RequestId: "0000-000"
}
this.setState({ data });
}
render() {
return (
<Text value={this.state.data["RequestId"]} />
);
}
}
// Render it
ReactDOM.render(
<Form />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>
What happen in your case is the child component mount before the logic change from the parent. Here a way to make it work. Also what you can do it's use the componentDidUpdate lifecycle method to trigger the change.
Remember componentDidMount get call only ONE time. So at the moment the parent get it the child is already mount. But as you can see the value of the input is filled that's because react component rerender on props change. BUT not REMOUNT.
With the if part here, the component render only when data RequestId is filled, so we can then trigger the componentDidMount with the value you want.
class Text extends React.Component {
componentDidMount(){
console.log(this.props.value);
}
render() {
return (
<div>
<input type="text" value={this.props.value} />
</div>
);
}
}
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {}
};
}
componentDidMount(){
let data = {
RequestId: "0000-000"
}
this.setState({ data });
}
render() {
if (!this.state.data["RequestId"]) { return null }
return (
<Text value={this.state.data["RequestId"]} />
);
}
}
// Render it
ReactDOM.render(
<Form />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Reactjs call componentWillMount of parent component

I have two components as below:
class Parent
{
componentWillMount () {
console.log('parent componentWillMount');
}
}
class Child extends Parent
{
componentWillMount () {
console.log('child componentWillMount');
}
}
But when the child component is loaded the componentWillMount method of the parent component is not loaded automatically. How do you call componentWillMount method of the parent component ?
Thanks
class Child extends Parent
{
componentWillMount () {
super.componentWillMount() ; //parent componentWillMount
console.log('child componentWillMount');
}
}
explain :
Child#componentWillMount overrides Parent#componentWillMount. So :
if you need only logic of Parent#componentWillMount without adding extra-logic, it is recommended to remove componentWillMount from Child .
If you need to call Parent#componentWillMount with appending some logic, retain Child#componentWillMount and call inside it super.componentWillMount();
You can call a parent's method in the follow manner:
class Child extends Perent {
componentWillMount () {
super.componentWillMount();
// Insert your child specific code here
}
}
But as Ben Nyrberg already mentioned in the comments it's not a good practice.
The good practice of reusing components code by following the React way is with components composition:
class Parent extends React.Component {
componentWillMount() {
// Reusable functionality here
}
render() {
return {this.props.children}
}
}
class Child extends React.Component {
componentWillMount() {
// Child specific functionality
}
render() {
return <div>Whatever you want</div>
}
}
class App extends React.Component {
render() {
return <Parent>
<Child />
</Parent>
}
}

ReactCSSTransitionGroup componentWillLeave not called

Im trying to play around with ReactCssTransition but somehow the event is not called(componentWillLeave)
Here's my component
import React, { Component } from 'react'
import TransitionGroup from 'react-addons-css-transition-group'
export default class TransitionComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
let {componentKey} = this.props
<TransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={500}>
<Item key={"item"+componentKey} />
</TransitionGroup>
);
}
}
And the child component
class Item extends Component {
componentDidEnter() {
console.log("component did enter");
}
componentWillLeave(callback) {
console.log("component will leave");
}
render() {
return (
<div>Item</div>
)
}
}
Any clue? Thanks!
I had similar issue caused by not calling the callback within the "componentWillEnter" function. Quote from React documentation
It will block other animations from occurring until callback is called
class Item extends Component {
componentWillEnter(callback) {
console.log("component will enter");
callback();
}
componentDidEnter() {
console.log("component did enter");
}
componentWillLeave(callback) {
console.log("component will leave");
callback();
}
render() {
return (
<div>Item</div>
)
}
}
Please excuse me as I am new to React myself but my understanding is that when components are mounted/unmounted you will not get the componentDidEnter() and componentWillLeave() lifecycle hooks.
All you have at your disposal is componentDidMount() and componentWillUnmount().
So replace the above portion with this and you should see your console logs:
componentDidMount() {
console.log('Component did mount');
}
componentWillUnmount() {
console.log('Component will unmount');
}
I believe if you want access to all of the lifecycle hooks you need to use ReactTransitionGroup instead, I have not yet figured out how to implement this though.
There is a good article on it on Medium though where the author explains it quite well.
There is a bit in the article where she talks about wrapping her child component with the ReactTransitionGroup component and I believe that is what you are looking for. Basically wrapping it around your current <Item />...

Categories

Resources