Unable to change state - reactjs

Expected behaviour: The app should display John at first and then I change the state (name) to George (setTimeout) so that should be displayed.The state doesn't seem to change though.Any ideas?
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state={name:"John"};
}
render() {
setTimeout(() => {
this.setState=({name:"George"})
}, 2000)
return (
<div>
{this.state.name}
</div>
);
}
}
export default App;

In comments you got the way to make your code working. But I would like to add an answer here with the message that it is not good idea to change the state of your component in the render() function.
As when your state changes render() function will be called, which will call setTimeout, it will again change the state ... so you will go into infinite loop of rendering your component.
The right way of during this is to have you setTimeout in the componentDidMount() function of your component.

Related

How can i refresh my child componet by using a button click on parent componet?

I am new to this stackoverflow world. Please help me here. How can i refresh the child component based on the button click from the parent component. For example, i have a button in parent component called refresh and not passing any state variables or props to child component. but i want the child component to loaded again based on the button click of parent. I tried adding a state variable, but it was not updating the child component.
parent component:
import React from "react";
import ChildComponentForRefreshTesting from "./ChildComponentForRefreshTesting";
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { isRefreshClicked : false };
}
submit() {
this.setState({ isRefreshClicked: true }, () => this.setState({isRefreshClicked: false}));
}
render() {
return (
<div>
<h1>Parent Component ------<button onClick={this.submit}>Refresh</button></h1>
<ChildComponentForRefreshTesting />
</div>
)
}
}
export default MyComponent;
child component:
import React from 'react'
function ChildComponentForRefreshTesting() {
return (
<div>
child component
<br />
</div>
)
}
export default ChildComponentForRefreshTesting;
Changing state should re-render the current component and all the child components inside it.
I ran your code and there is a mistake with how you defined the setState method. You need to use arrow function, otherwise this will be undefined.
So change your submit button like following and it should work.
submit = () => {
this.setState({ isRefreshClicked: true });
};
Here's the stackblitz: https://stackblitz.com/edit/react-f5q3n8?file=src/MyComponent.js
In class components, you can call this.forceUpdate() method to force a rerender.
https://reactjs.org/docs/react-component.html#forceupdate

A Component changing its props?

So, I want my component to render only when I do it (eg. when it is clicked.) . I don't want it to re-render when its props changes.
So, my idea was to have the parent pass a wasClicked='true' prop, when it is clicked, which I change to 'false' once it is rendered and have a condition in the render body to only render when wasClicked is true.
How is this possible?
With class components, you can decide if you want to update component with a lifecycle method called shouldComponentUpdate. With a functional component, you can decide if the component should update with React.memo
That should be easy, lets say this is a simple component that only renders when wasClicked is true:
simpleComponent.js:
import react from "react";
const SimpleComponent = (props) => {
return <p> some text </p>;
};
export default SimpleComponent;
App.js;
import react from "react";
import SimpleComponent from "./simpleComponent.js";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
wasClicked: false, //this is the state for wasClicked
};
}
//this is the function that changes wasClicked to true when the component is clicked
handleClick = () => {
this.setState({ wasClicked: true });
};
render() {
return (
<>
{this.state.wasClicked && ( //this will only render SimpleComponent when wasClicked is true
<SimpleComponent
onClick={this.handleClick}
wasClicked={this.state.wasClicked}
/>
)}
</>
);
}
}
export default App;
Hope this was helpful and clear, thanks

Link Props to State ReactJS

I'am using reactjs and Redux to transfer data from a page to another page,
in the first page i'am dispatching an action to save the values,
this works good
In the second page, I have a component using this saved values
so the this.props.values give me exactely the values
but in this component i have to use in the render part the this.state.values
Is there a way to link this.props.values to my this.state.values in my second page ?
Is there a way to link this.props.values to my this.state.values in my second page ?
If that's all you want, the best way to put props into state is in the constructor
class Component extends React.Componet {
constructor(props) {
super(props)
this.state = { values: props.values || [] } // [] or some default value
}
}
just make sure you handle the case where the props value changes using componentWillReceiveProps
componentWillReceiveProps (nextProps) {
if (!equals(this.props.values, nextProps.values)) {
this.setState({ values: nextProps.values })
}
}
equals is whatever you want it to be (==, lodash#deepEquals, etc)
You can use class like this or if you are writing in function style, pass props as argument and simply call in return as {props.values}
import React, {Component} from 'react';
class testSample extends Component {
constructor(props) {
super(props)
console.log(props.value); //check whether you are receiving values in browser console
this.state = { values: props.values }
}
render(){
return(
<div>{this.state.values} </div>
)
}
}
export default testSample
or you can directly access them like this instead assigning to state again.
import React, {Component} from 'react';
class testSample extends Component {
constructor(props) {
super(props)
console.log(props.value); //check whether you are receiving values in browser console
}
render(){
return(
<div>{this.props.values} </div>
)
}
export default testSample

Unmounting a React component the correct way

export class Child extends React.Component{
unmount() {
const node = ReactDOM.getDOMNode(this);
ReactDOM.unmountComponentAtNode(node );
}
render() {
return <button onClick={this.unmount.bind(this)}>Unmount</button>
}
}
For the above sample component, would it possible to unmount it on click using unmountComponentAtNode?
React application is always a components composition, or in different words - components tree. It means that every component has parent component, which renders it, it is only falsy statement for root component, mostly we name it App, but we do not talk about it in that question. Above all, we can say that a component, which needs to be unmounted, always has a parent component.
As we did the assumption in first paragraph, the correct way of unmounting React component is to remove it from render method in parent component. It can be done in many ways, the simplest is just an conditional component rendering like:
class IAmParentComponent extends React.Component {
render() {
return (<div>{this.state.show && <YourChildComponentToUnmount/>}</div>)
}
}
Above example shows IAmParentComponent as container component which holds a state, and the YourChildComponentToUnmount will render if this.state.show is true, will unomount after state change from true to false.
Back to your code with callback, the callback should be send into component by props, and the parent component should do the state change related to removing the component from render tree, what exactly will start unmount phase of the component, and finally component will be removed from UI.
In conclusion, component unmount should be in responsibility of component above it, component should not unmount itself.
This is not the way react.
The best way to unmount an element is to tell the parent to remove the child from the rendered children of the parent.
Look at this example.
Here we have the CardContainer class and CardItem class.The CardItem item class has a delete self button. This method send an event to the parent container to remove itself from the rendered children.
const carddata = [
{key:1 ,name: 'Card A',visible:true},
{key:2 ,name: 'Card B',visible:true}
];
class CardItem extends React.Component {
constructor(props){
super(props)
this.handleClick=this.handleClick.bind(this);
}
componentWillUnmount(){
console.log('unmount')
}
handleClick(){
this.props.destroy(this.props.id)
}
render(){
return(<div>
Card
<button onClick={this.handleClick} >delete</button>
</div>)
}
}
class CardContainer extends React.Component {
constructor(props){
super(props)
this.state = {data: carddata};
this.destroy = this.destroy.bind(this);
}
destroy(elementKey){
console.log(elementKey)
debugger
let result = this.state.data.filter(item=> item.key !==elementKey);
this.setState({data: result});
}
render(){
return (<div>
Card Container
{this.state.data.map((card,index) => {
return <CardItem key={card.key} id={card.key} name={card.name} destroy={this.destroy}/>
})
}
</div>)
}
}

Why componentWillReceiveProps is not called?

At child, I need to listen for state changed at parent, I tried to do so as:
Child
class deleteDriverAlert extends Component {
constructor(props) {
super(props);
this.state = {
show: false
};
}
componentWillReceiveProps(nextProps) {
console.log("componentWillReceiveProps . . . . .");
this.setState({ show: nextProps.dataset.showDeleteAll });
}
render() {
return (
<SweetAlert
warning
showCancel
confirmBtnText="Yes, delete it!"
confirmBtnBsStyle="danger"
cancelBtnBsStyle="default"
title="Are you sure?"
onConfirm={this.props.dataset.onConfirm}
onCancel={this.props.dataset.onCancel}
show={this.state.show}
>
You will not be able to recover this imaginary file!
</SweetAlert>
);
}
}
export default deleteDriverAlert;
then, in the parent, I add the child as:
<deleteDriverAlert data-showDeleteAll={this.state.show_delete_all} data-onConfirm={this.deleteDriver} data-onCancel={this.onCancelDelete} />
now, although I do change the property state show_delete_all at parent, componentWillReceiveProps is not called at child.
Any idea?
A few things, firstly you don't need to set the props into the state of the child component to be able to use them dynamically. The problem is most likely with the way you are changing the state in the parent.
Here is a simple example of the same thing you are trying to do:
The Parent component has its own state and a method to change it which is bound to the parent context and is flipped with a button. Then the state is passed to the child as a prop:
import React, { Component } from 'react';
import Child from './Child';
class Parent extends Component {
constructor(props) {
super(props);
this.state = { show: false };
this.flipShow = this.flipShow.bind(this);
}
flipShow(){
this.setState({show: !this.state.show})
}
render() {
return (
<div>
<p>Parent</p>
<button onClick={this.flipShow}>Show</button>
<Child show={this.state.show} />
</div>
);
}
}
export default Parent;
Then the child simply passes the prop through. Note: in the example below the componentWillReceiveProps is unnecessary but I only put it there to show that it does fire with this set up.
import React, { Component } from 'react';
import SweetAlert from './SweetAlert';
class Child extends Component {
componentWillReceiveProps(nextProps){
console.log("receiving new props");
}
render() {
return (
<SweetAlert
show={this.props.show}
/>
);
}
}
export default Child;
TL;DR
If componentWillReceiveProps isn't firing, it's a problem with the Parent component and the way it is setting the prop value not the child.
I may be wrong, but I don't think react will re-render the child component when the parent component change state, which makes sense because the state is a local thing specific to that component. But since you're not using a state management library it would make more sense to use the new React Context API in this scenario, to pass changing data down to the Child component, and it looks pretty straightforward
https://reactjs.org/docs/context.html

Resources