react setstatus issue in the application - reactjs

I am trying to change setState using button click. Please check my code
export class Mystate extends Component {
constructor( ) {
super();
this.state = {
message:'Click Me Friends'
}
}
clickme = () => {
alert('my alert');
this.setState = ({
message: 'Thank You'
})
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
<button onClick={() =>this.clickme()}> Click </button>
</div>
);
}
}
I called the alert. It's working well, but state did not update. How do I update it?

The setState() is a function and you need to call:
this.setState({
message: "Thank You"
})
Remove the = after that in your code. Also, you can remove the following:
constructor() {
super();
this.state = {
message: "Click Me Friends"
}
}
And replace with:
state = {
message: "Click Me Friends"
}
Full Code
import React, { Component } from "react";
export default class Mystate extends Component {
state = {
message: "Click Me Friends"
};
clickme = () => {
alert("my alert");
this.setState = {
message: "Thank You"
};
};
render() {
return (
<div>
<h1>{this.state.message}</h1>
<button onClick={() => this.clickme()}> Click </button>
</div>
);
}
}

Pass the updated object to your setState method like below
this.setState({ message: "Thank You"});
Working Code - https://codesandbox.io/s/sweet-frost-gzcu1?file=/src/App.js:253-304

Don't assignment. setState() is a method you need to call it.
clickme = () => {
alert('my alert');
this.setState({
message: 'Thank You'
})
}
As you are using the arrow function you can avoid the inline arrow function here
instead of onClick={() =>this.clickme()} use like
<button onClick={this.clickme}> Click </button>

Related

Why is this.state not updated real-time after setState is issued?

So I'm trying to simulate the state by clicking a button. The 'before' status seems to have the correct value, but why is the 'after' not displaying the correct value even if the setState is already hit by the code?
class App extends Component {
constructor(){
super()
this.state = {isLoggedIn: false}
this.OnClick = this.OnClick.bind(this);
}
OnClick(){
this.setState(prev =>
{
return (prev.isLoggedIn = !this.state.isLoggedIn);
})
console.log(`After setState value: ${this.state.isLoggedInstrong text}`) // setState is done, why is this.state displaying incorrect value?
}
render()
{
console.log(`Before setState value: ${this.state.isLoggedIn}`)
return <Login isLoggedIn={this.state.isLoggedIn} OnClick={this.OnClick} />
}
}
import React from "react";
class Login extends React.Component
{
render()
{
const {isLoggedIn, OnClick} = this.props;
return (
<div>
<button onClick={OnClick} >{isLoggedIn ? "Log Out" : "Log In"} </button>
</div>
)
}
}
export default Login;
OUTPUT:
"Before setState value: false"
(Initial display, button value is: Log In)
When button is clicked:
"After setState value: false" <------ why false when setState has been hit already? Not real-time update until Render is called?
"Before setState value: true"
(Button value is now: Log Out)
The main problem I see in your code is you’re trying to mutate the state.
this.setState(prev => {
return (prev.isLoggedIn = !this.state.isLoggedIn);
})
You have to merge to the state not mutate it. You can do it simply by returning an object like this.
this.setState((prev) => {
return { isLoggedIn: !prev.isLoggedIn };
});
This will fix all the weird behaviours in your code.
Full Code
App.js
import { Component } from "react";
import Login from "./Login";
class App extends Component {
constructor() {
super();
this.state = { isLoggedIn: false };
this.OnClick = this.OnClick.bind(this);
}
OnClick() {
this.setState((prev) => {
return { isLoggedIn: !prev.isLoggedIn };
});
console.log(`After setState value: ${this.state.isLoggedIn}`);
}
render() {
console.log(`Before setState value: ${this.state.isLoggedIn}`);
return <Login isLoggedIn={this.state.isLoggedIn} OnClick={this.OnClick} />;
}
}
export default App;
Login.js
import { Component } from "react";
class Login extends Component {
render() {
const { isLoggedIn, OnClick } = this.props;
return (
<div>
<button onClick={OnClick}>{isLoggedIn ? "Log Out" : "Log In"} </button>
</div>
);
}
}
export default Login;
CodeSandbox - https://codesandbox.io/s/setstate-is-not-update-the-state-69141369-efw46
try this
this.setState({
isLoggedIn:!this.state.isLoggedIn
})
or
this.setState(prev => ({
isLoggedIn:!prev.isLoggedIn
}))

Why does my "Audio-Button" don`t play a sound (onClick)

I am struggeling on finding out why my button dont play a sound when I click on it. The console.log() test works fine, but the -part dont. I also tried some npm-packets to solve the problem, but it seems like my code has a general problem. Whats wrong with it? Can someone help me?
The main.js :
import Button from './button';
class Drumpad extends Component {
constructor(props) {
super(props);
this.state = {
Q:
{
id: 'Q',
name: 'Q',
src: 'https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3'
},
}
}
render() {
return (
<div style={test}>
<div id='row1'>
<Button cfg={this.state.Q}/>
</div>
</div>
)
}
}
And the button.js:
class Button extends Component {
constructor(props) {
super(props);
this.state = {
}
}
handleClick = () => {
console.log(this.props.cfg.src);
return (
<audio ref='audioClick' src={this.props.cfg.src} type='audio/mp3' autoPlay>
);
};
render() {
return (
<div>
<button style={buttonStyle} onClick={this.handleClick}>
<h1>{this.props.cfg.name}</h1>
</button>
</div>
)
}
}
The handleClick method in button.js returns an <audio> element, which is redundant, since you would like to play the sound onClick.
Instead I used a Audio constructor to create an instance of the audio clip, using the url provided as props, which I set to state.
Then I use a callback to invoke the play() method on it.
handleClick = () => {
const audio = new Audio(this.props.cfg.src);
this.setState({ audio }, () => {
this.state.audio.play();
});
};
So your button.js becomes something like this:
import React, { Component } from "react";
const buttonStyle = {};
export default class Button extends Component {
constructor(props) {
super(props);
this.state = {
audio: false
};
}
handleClick = () => {
console.log(this.props.cfg.src);
const audio = new Audio(this.props.cfg.src);
this.setState({ audio }, () => {
this.state.audio.play();
});
};
render() {
return (
<div>
<button style={buttonStyle} onClick={this.handleClick}>
<h1>{this.props.cfg.name}</h1>
</button>
</div>
);
}
}
Your main.js remains as is.
Here is a working codesandbox.

Change State whenever button is clicked back and forth in React?

So I know how to change state when the button is clicked once, but how would I change the new state back to the previous state when the button is clicked again?
You can just toggle the state.
Here's an example using a Component:
class ButtonExample extends React.Component {
state = { status: false }
render() {
const { status } = this.state;
return (
<button onClick={() => this.setState({ status: !status })}>
{`Current status: ${status ? 'on' : 'off'}`}
</button>
);
}
}
Here's an example using hooks (available in v16.8.0):
const ButtonExample = () => {
const [status, setStatus] = useState(false);
return (
<button onClick={() => setStatus(!status)}>
{`Current status: ${status ? 'on' : 'off'}`}
</button>
);
};
You can change the 'on' and 'off' to anything you want to toggle. Hope this helps!
Here is my example of show on toggle by using React Hook without using useCallback().
When you click the button, it shows "Hello" and vise-versa.
Hope it helps.
const IsHiddenToggle = () => {
const [isHidden, setIsHidden] = useState(false);
return (
<button onClick={() => setIsHidden(!isHidden)}>
</button>
{isHidden && <p>Hello</p>}
);
};
Consider this example: https://jsfiddle.net/shanabus/mkv8heu6/6/
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
buttonState: true
}
this.toggleState = this.toggleState.bind(this)
}
render() {
return (
<div>
<h2>Button Toggle: {this.state.buttonState.toString()}</h2>
<button onClick={this.toggleState}>Toggle State</button>
</div>
)
}
toggleState() {
this.setState({ buttonState: !this.state.buttonState })
}
}
ReactDOM.render(<App />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Here we use a boolean true/false and flip between the two states. If you are looking to use some other custom data as your previous state, just create a different variable for that.
For example:
this.state = { previousValue: "test", currentValue: "new thing" }
This will toggle to previous and new value :
constructor() {
super();
this.state = {
inputValue: "0"
}
}
render() {
return (
<div>
<input
type="button"
name="someName"
value={this.state.inputValue}
onClick={() =>
this.state.inputValue === "0"
? this.setState({
inputValue: "1"
})
:
this.setState({
inputValue: "0"
})
}
className="btn btn-success"
/>
</div>
)
}
Description :
If the current value = 0, then set the value to 1, and vice versa.
This is useful if you have a lot of inputs. So, each input has a different state or condition.
You must save the previous state. You could even make previous state part of your actual state - but I'll leave that as an exercise for the OP (Note: you could preserve a full history of previous states using that technique). Unfortunately I cannot yet write examples from the top of my head using the new hooks feature:
class MyComponent extends ReactComponent {
prevState = {}
state = {
isActive: false,
// other state here
}
handleClick = () => {
// should probably use deep clone here
const state = Object.assign({}, this.state);
this.setState(state.isActive ? this.prevState : Object.assign(state, {
isActive: true,
// other state here
});
this.prevState = state;
}
render() {
return <button onClick={this.handleClick}>Toggle State</button>
}
}
in state:
this.state = {toggleBtn: ""}
in your button:
<button key="btn1" onClick={() => this.clickhandler(btn1)}>
{this.state.toggleBtn === ID? "-" : "+"}
</button>
in your clickhandler:
clickhandler(ID) {
if (this.state.toggleBtn === ID) {
this.setState({ toggleBtn: "" });
} else {
this.setState({ toggleBtn: ID});
}

Unhandled Rejection (TypeError): Cannot read property 'setState' of undefined

I know that there are plenty of answers on this, for example this one. I did add the .bind(this) in the component constructor. I also tried the fat arrow method (fakeApiCall = ()=>{ ... }) but when I click Change Me, this error still displays:
import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
constructor(props){
super(props);
this.state = {
count : 1000
};
this.fakeApiCall = this.fakeApiCall.bind(this);
}
fakeApiCall (){
axios.get('https://jsonplaceholder.typicode.com/users')
.then(function(response){
// the response comes back here successfully
const newCount = response.data.length;
// fail at this step
this.setState({ count : Math.floor(newCount) });
});
}
render() {
return (
<div className="App">
<span style={{ fontSize : 66 }}>{this.state.count}</span>
<input type='button' onClick={this.fakeApiCall} value='Change me' />
</div>
);
}
}
export default App;
Your fakeApiCall function is bound to your context, but the function callback in axios is not.
To solve this, you can use an arrow function, as they automatically bind with your class. You can also do it for fakeApiCall and remove it's binding :
class App extends Component {
constructor(props) {
super(props);
this.state = {
count: 1000
};
}
fakeApiCall = () => {
axios.get('https://jsonplaceholder.typicode.com/users')
.then(response => { //This is an arrow function
const newCount = response.data.length;
this.setState({ count: Math.floor(newCount) });
});
}
render() {
return (
<div className="App">
<span style={{ fontSize: 66 }}>{this.state.count}</span>
<input type='button' onClick={this.fakeApiCall} value='Change me' />
</div>
);
}
}

Reactjs setState not updating for this one function only

For this application, clicking a listed item once should create a button component underneath this listed item. Clicking the button should cause this listed item to be deleted.
I am currently facing difficulty trying to 'delete' the listed item after the button is clicked. Here is the code that went wrong (this is found in CountdownApp component) :
handleDelete(index) {
console.log('in handleDelete')
console.log(index)
let countdownList = this.state.countdowns.slice()
countdownList.splice(index, 1)
console.log(countdownList) // countdownList array is correct
this.setState({
countdowns: countdownList
}, function() {
console.log('after setState')
console.log(this.state.countdowns) // this.state.countdowns does not match countdownList
console.log(countdownList) // countdownList array is still correct
})
}
In the code above, I removed the item to be deleted from countdownList array with splice and tried to re-render the app with setState. However, the new state countdowns do not reflect this change. In fact, it returns the unedited state.
I have also tried the following:
handleDelete(index) {
this.setState({
countdowns: [] // just using an empty array to check if setState still works
}, function() {
console.log('after setState')
console.log(this.state.countdowns)
})
}
In the code above, I tried setting state to be an empty array. The console log for this.state.countdowns did not print out an empty array. It printed out the unedited state again
This is the only event handler that isn't working and I have no idea why (main question of this post) :/
If I have 'setstate' wrongly, why does the other 'setState' in other parts of my code work?? (I would like to request an in-depth explanation)
This is all my code for this app (its a small app) below:
import React from 'react'
import ReactDOM from 'react-dom'
class DeleteButton extends React.Component {
render() {
return (
<ul>
<button onClick={this.props.onDelete}>
delete
</button>
</ul>
)
}
}
class Countdown extends React.Component {
render () {
//console.log(this.props)
return (
<li
onClick={this.props.onClick}
onDoubleClick={this.props.onDoubleClick}
>
{this.props.title} - {this.props.days}, {this.props.color}
{this.props.showDeleteButton ? <DeleteButton onDelete={this.props.onDelete}/> : null }
</li>
)
}
}
const calculateOffset = date => {
let countdown = new Date(date)
let today = new Date
let timeDiff = countdown.getTime() - today.getTime()
let diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24))
return diffDays
}
class CountdownList extends React.Component {
countdowns() {
let props = this.props
// let onClick = this.props.onClick
// let onDoubleClick = this.props.onDoubleClick
let rows = []
this.props.countdowns.forEach(function(countdown, index) {
rows.push(
<Countdown
key={index}
title={countdown.title}
days={calculateOffset(countdown.date)}
color={countdown.color}
showDeleteButton={countdown.showDeleteButton}
onDelete={() => props.onDelete(index)}
onClick={() => props.onClick(index)}
onDoubleClick={() => props.onDoubleClick(index)}
/>
)
})
return rows
}
render() {
return (
<div>
<ul>
{this.countdowns()}
</ul>
</div>
)
}
}
class InputField extends React.Component {
render() {
return (
<input
type='text'
placeholder={this.props.placeholder}
value={this.props.input}
onChange={this.props.handleInput}
/>
)
}
}
class DatePicker extends React.Component {
render() {
return (
<input
type='date'
value={this.props.date}
onChange={this.props.handleDateInput}
/>
)
}
}
class CountdownForm extends React.Component {
constructor(props) {
super(props)
this.state = {
title: this.props.title || '',
date: this.props.date || '',
color: this.props.color || ''
}
}
componentWillReceiveProps(nextProps) {
this.setState({
title: nextProps.title || '',
date: nextProps.date || '',
color: nextProps.color || ''
})
}
handleSubmit(e) {
e.preventDefault()
this.props.onSubmit(this.state, this.reset())
}
reset() {
this.setState({
title: '',
date: '',
color: ''
})
}
handleTitleInput(e) {
this.setState({
title: e.target.value
})
}
handleDateInput(e) {
this.setState({
date: e.target.value
})
}
handleColorInput(e) {
this.setState({
color: e.target.value
})
}
render() {
return (
<form
onSubmit={(e) => this.handleSubmit(e)}
>
<h3>Countdown </h3>
<InputField
placeholder='title'
input={this.state.title}
handleInput={(e) => this.handleTitleInput(e)}
/>
<DatePicker
date={this.state.date}
handleDateInput={(e) => this.handleDateInput(e)}
/>
<InputField
placeholder='color'
input={this.state.color}
handleInput={(e) => this.handleColorInput(e)}
/>
<button type='submit'>Submit</button>
</form>
)
}
}
class CountdownApp extends React.Component {
constructor() {
super()
this.state = {
countdowns: [
{title: 'My Birthday', date: '2017-07-25', color: '#cddc39', showDeleteButton: false},
{title: 'Driving Practice', date: '2017-07-29', color: '#8bc34a', showDeleteButton: false},
{title: 'Korean BBQ', date: '2017-08-15', color: '#8bc34a', showDeleteButton: false}
]
}
}
handleCountdownForm(data) {
if (this.state.editId) {
const index = this.state.editId
let countdowns = this.state.countdowns.slice()
countdowns[index] = data
this.setState({
title: '',
date: '',
color: '',
editId: null,
countdowns
})
} else {
data.showDeleteButton = false
const history = this.state.countdowns.slice()
this.setState({
countdowns: history.concat(data),
})
}
}
handleDelete(index) {
console.log('in handleDelete')
console.log(index)
let countdownList = this.state.countdowns.slice()
countdownList.splice(index, 1)
console.log(countdownList)
this.setState({
countdowns: countdownList
}, function() {
console.log('after setState')
console.log(this.state.countdowns)
})
}
handleCountdown(index) {
const countdownList = this.state.countdowns.slice()
let countdown = countdownList[index]
countdown.showDeleteButton = !countdown.showDeleteButton
this.setState({
countdowns: countdownList
})
}
handleDblClick(index) {
const countdownList = this.state.countdowns
const countdown = countdownList[index]
this.setState({
title: countdown.title,
date: countdown.date,
color: countdown.color,
editId: index
})
}
render() {
return (
<div>
<CountdownForm
title={this.state.title}
date={this.state.date}
color={this.state.color}
onSubmit={(data) => {this.handleCountdownForm(data)}}
/>
<CountdownList
countdowns={this.state.countdowns}
onDelete={(index) => this.handleDelete(index)}
onClick={(index) => this.handleCountdown(index)}
onDoubleClick={(index) => this.handleDblClick(index)}
/>
</div>
)
}
}
ReactDOM.render(
<CountdownApp />,
document.getElementById('app')
)
I managed to find the answer to my own question!
setState worked as expected. The bug was due to <li> container that wrapped the event handler.
Clicking <li> causes it to call onClick event (which is managed by handleCountdown function in CountdownApp component) which causes it to setState.
As the delete button was wrapped in <li> container, clicking the delete button calls 2 event listeners - handleCountdown and handleDelete. handleCountdown is called twice in this case, once from clicking <li> to expand and the next call when the delete button is clicked.
There is a high chance that the last async setState dispatched from handleCountdown overwrites handleDelete's setState. Hence, the bug.
Here is changes: (I recoded everything again so the names might differ a little but the logic stays the same)
class Countdown extends React.Component {
render () {
return (
<li>
<div onClick={this.props.onClick} > // Add this div wrapper!
{this.props.title} - {this.props.days}, {this.props.color}
</div>
{this.props.toShow ?
<ButtonsGroup
onDelete={this.props.onDelete}
onEdit={this.props.onEdit}
/>
: null}
</li>
)
}
}
So the solution is to separate the clickable area and the buttons. I added a div wrapper over the text in <li> so whenever the text in <li> is clicked, the added <ul> will be out of onClick event handler area.

Resources