I have a component and i am able to change the state of checkbox item when i click on a button.
I also want to be able to change the state in another button-click, which has lot more logic in it.
The issue i am having in that when the code goes into the condition it does not set the state back to false.
I tried changing the state again using setstate but it does not change the state of the enabledCheckBox.
this.setState({
enabledCheckBox: !this.state.enabledCheckBox,
})
Can anyone tell me what the issue is?
Thanks
class Customer extends Component {
constructor(props) {
super(props)
this.state = {
...props,
enabledCheckBox: false
};
}
//this works
onChangeCheckBox=()=>{
this.setState({
enabledCheckBox: !this.state.enabledCheckBox,
})
}
//cant get this to work
handleCustomerClick = (event) => {
if (this.state.enabledCheckBox) {
this.setState({
enabledCheckBox: !this.state.enabledCheckBox,
})
}
https://codesandbox.io/s/1y0zywy727
I included a working example. It does similar things as how you described.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
enabledCheckBox: false
};
}
onClick = () => {
this.setState({ enabledCheckBox: !this.state.enabledCheckBox });
};
render() {
return (
<div>
<input
type="checkbox"
value={"some checked box"}
checked={this.state.enabledCheckBox}
onChange={this.onClick}
/>
{this.state.enabledCheckBox ? <div>Blue</div> : <div>Red</div>}
<button onClick={this.onClick}>Click to Change Color</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Both input and div are using this.state.enabledcheckbox. So if you check the box, not only the box will be checked but also the div's "color" would change with it. Same thing as clicking the button
your this is being bound incorrectly try this;
handleCustomerClick = (event) => {
let {enabledCheckBox} = this.state;
this.setState({
enabledCheckBox: !enabledCheckBox,
});
}
If you really need the if statement you could do the following;
handleCustomerClick = (event) => {
let {enabledCheckBox} = this.state;
let data;
if (enabledCheckBox) {
data = {
enabledCheckBox: !enabledCheckBox
}
}
this.setState(data);
}
Related
I'm trying to create a todo app in React. I'm currently trying to print the input when i press the + button, but it is not working. Can anyone help to check my syntax!
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(){
super();
this.state = {
value: '',
tasks: []
};
this.handleChange = this.handleChange.bind(this)
this.addItem = this.addItem.bind(this)
}
handleChange(event) {
this.setState({
value: event.target.value
})
}
addItem(){
this.state.tasks.push(this.state.value)
}
render(){
return(
<div>
<input type="text" value={this.state.value} onChange={this.handleChange}></input>
<button onClick={this.addItem}>+</button>
<button>-</button>
<h1>{this.state.tasks}</h1>
</div>
)
}
}
export default App;
To change the state you should use this.setState. Refer to https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly. Reading React documentation might save you a lot of time overall.
Modifying state directly is not the correct way!
instead use setState:
this.setState({
tasks: this.state.tasks.concat(this.state.value)
})
You need to setState task
addItem() {
const newTask = [this.state.value, ...this.state.tasks];
this.setState({ tasks: newTask });
this.setState({ value: "" });
}
enter image description here
I am trying to validate a form field and have the following code:
import React, {Component} from 'react';
import {TextField} from '#material-ui/core';
class ProductField extends Component {
constructor(props) {
super(props);
this.isValid = this.isValid.bind(this);
}
isValid() {
console.log("Checking if valid...");
}
componentDidMount() {
console.log("this isn't working");
}
render() {
return (
<TextField style={{width:"100%"}} id={this.props.label} label={this.props.label} variant="outlined"
hintText={this.props.label}
helperText={this.props.meta.touched && this.props.meta.error}
onChange={event => {
console.log("changed");
const { value } = event.target;
this.setState({ searchValue: value });
}}
{...this.props.input}
/>
);
}
}
export default ProductField;
When onChange is called, I want to check the state of the TextField, and if this.props.meta.error is not empty I want to set the Text Field prop "error" and if it is empty then I want to unset the "error" prop.
Right now, even the console.log("Checking if valid...") isn't working, suggesting that the onChange event isn't being fired at all.
What am I doing wrong?
You have several issues in your code:
You need to initialize your state in the constructor, so the state will be reliable with you Textfield, also you have to set a property in the state that will handle if the field is valid or is an `error'.
You need to create a method to validate your TextField value, and inside this method update the state based on the validity of field, here you can add the this.props.meta.error or anything else that is validating your values, and remember to call the method that will validate your value after the state has been properly changed, maybe using it as a callback on the setStatemethod .
You have to add a prop to your TextField component to catch if it is an error or if it is valid.
import React, { Component } from "react";
import { TextField } from "#material-ui/core";
class App extends Component {
constructor(props) {
super(props);
this.state = {
searchValue: "",
isValid: false
};
this.isValid = this.isValid.bind(this);
}
isValid() {
console.log("Checking if valid...");
this.setState({ isValid: this.state.searchValue.length > 6 });
}
componentDidMount() {
console.log("this isn't working");
}
render() {
return (
<TextField
style={{ width: "100%" }}
id={this.props.label}
label={"example"}
variant="outlined"
error={!this.state.isValid && this.state.searchValue != ""}
onChange={event => {
console.log("changed");
const { value } = event.target;
this.setState({ searchValue: value }, () => {
this.isValid();
});
}}
/>
);
}
}
export default App;
Check this sandbox for a working example
I am changing the state and I can see in the console.log the new state, however, the TextArea does not show the new state, but only when its first displayed.
Here is my implementation:
import React, {Component} from 'react';
import {TextArea} from "semantic-ui-react";
class Output extends Component {
static myInstance = null;
state = { keys:[] }
updateState(){
// this method is called from outside..
this.setState({ keys:this.state.keys.push(0) });
// I can see that keys are getting increase
console.log(this.state.keys);
}
render() {
return (
<TextArea value={this.state.keys.length} />
);
}
}
TextArea will keep showing 0, although the length of state.keys increases..
Any idea?
Never mutate the state.
To update the state, use this syntax:
this.setState(prevState => ({
keys: [...prevState.keys, newItem]
}))
you dont call your updateState function to update your state , it just exists over there, for pushing 0 to your state in order to reRender your component with new state, you can call your method in componentDidMount like below:
componentDidMount = () => {
this.updateState()
}
this will excute your updateState function immediately after component mounts into the dom.
Here is the working example
Firstly you should call your function to update the state
Example on jsfiddle
class Output extends React.Component {
static myInstance = null;
state = { keys:[] }
componentDidMount(){
this.updateState();
}
updateState() {
const newKeys = [...this.state.keys,0]
this.setState({ keys:newKeys });
}
onTextareaChange(){}
render() {
return (
<textarea value={this.state.keys.length} onChange= {this.onTextareaChange} />
);
}
}
ReactDOM.render(<Output />, document.querySelector("#app"))
Here I try to clear ingredient when users click purchasing cancel, and set state purchasing false then ingredient clean, but state seems to be true. and doesn't clear ingredient from orders with realtime, even modal window cl what should i need to do ?
///Root Component
state = {
purchasing: false
}
purchaseCancleHandler = () => {
this.setState({purchasing: false
});
}
<OrderSummary
purchaseContinue = {
this.purchaseContinuewHandler
}
purchaseCancle = {
this.purchaseCancleHandler
}
/>
//Child component
import React, {Component} from 'react'
import Button from '../../UI/Button/Button'
import Aux from '../../../hoc/Aux'
class OrderSummary extends Component {
componentWillUpdate() {
//console.log('[OrderSummer] willupdate')
}
render ()
{
const ingredientSummary =Object.keys(this.props.ingredients)
.map(igkey => {
return <li key={igkey}><span style={{textTransform:'capitalize'}}>{igkey}</span>: {this.props.ingredients[igkey]}</li>
});
return(
<Aux>
<h3>Your Order</h3>
<p> A delicious Burger with the following ingredient</p>
<ul>
{ingredientSummary}
</ul>
<p>Total Price :<strong>{this.props.totalprice.toFixed(2)}</strong></p>
<p>Continure To Checkout ?</p>
<Button btnType="Danger" clicked={this.props.purchaseCancle}>CANCEL</Button>
<Button btnType="Success" clicked={this.props.purchaseContinue}>CONTINUE</Button>
</Aux>
);
}
}
export default OrderSummary;
state = {
purchasing: false
}
purchaseCancleHandler = () => {
this.setState({purchasing: false
});
}
<Button btnType="Danger" clicked={this.purchaseCancleHandler}>CANCEL</Button>
You don't need .props if it's declare in the same local state. Also, your function wasn't invoked spelled correctly (it was missing "Handler")
You're wanting to call a method defined on the component itself, not a prop passed to the component, so you need to use this.purchaseCancleHandler.
state = {
purchasing: false
}
purchaseCancleHandler = () => {
this.setState({
purchasing: false
});
}
<Button btnType="Danger" clicked={this.purchaseCancleHandler}>CANCEL</Button>
constructor(props) {
super(props)
this.state = {
purchasing: null
}
}
purchaseCancleHandler = () => {
this.setState({
purchasing: false // need set this value difference with initial value
});
}
// Child component
clicked = () => {
this.props.purchaseCancle()
}
<Button btnType="Danger" clicked={this.clicked}>CANCEL</Button>
To make sure component will render after setState, need set value for purchasing difference with initial value.
I am new to React. This is probably a noob question.
I want to change the "filteredFields" prop of my MeteorGriddle component when the user clicks a checkbox. My JSX:
const bookingsPage = () => {
let filteredFields = ['userName'];
const handleClick = (e) => {
if (e.target.checked) {
filteredFields = ['userEmail'];
// How to propagate this change to the MeteorGriddle?
}
}
return (
<div>
<label><input type="checkbox" defaultChecked="true" value="userEmail" onClick={handleClick}/>Email</label>
<MeteorGriddle filteredFields={filteredFields}/>
</div>
);
};
I see two ways of solving your problem.
The first and easy way to do this:
Turn your bookingsPage component into statefull component instead of functional,
then you'd be able to create state inside it, and then change the state on event alongside with passing it to MeteorGriddle component.
So the code would be:
class bookingsPage extends React.Component {
getInitialState = () => {
filteredFields: []
}
handleClick = (e) => {
if (e.target.checked) {
const newFilteredFields =
[ ...this.state.filteredFields ].push('userEmail');
this.setState({ filteredFields: newFilteredFields });
}
}
render() {
return (
<div>
<label>
<input
type="checkbox"
defaultChecked="true"
value="userEmail"
onClick={this.handleClick}
/>
Email
</label>
<MeteorGriddle
filteredFields={this.state.filteredFields}
/>
</div>
);
}
};
Second and harder way to do this:
Take a look on Redux. It solves a problem of data flow in React.
The basic concept is that when you check you checkbox, you dispatch an action into reducer (aka your global data storage for react components), and then GriddleComponent recieves new state of your application with fresh data inside which tells him the checkbox is checked.
Say if you want me to write an example based on yours for you.
As #Maxx says, you should use a component with state. Then when you call the setState method, it will render again, updating the props of the children.
In your case this should work (also using ES6 notation):
import React from 'react';
import MeteorGriddle from '...whatever path...';
class bookingsPage extends React.Component {
state = {
filteredFields: ['userName']
};
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
if (e.target.checked) {
this.setState({
...this.state, //This is just a good practice to not overwrite other properties
filteredFields: ['userEmail']
});
}
}
render() {
const { filteredFields } = this.state;
return(
<div>
<label>
<input type="checkbox" defaultChecked="true" value="userEmail"
onChange={this.handleChange}/>Email
</label>
<MeteorGriddle filteredFields={filteredFields}/>
</div>
);
}
}
There are number of ways to achieve this, you can just try like the below code,
import React from 'react';
class bookingsPage extends React.Component {
state = {
filteredFields: ['userName']
};
constructor(props) {
super(props);
}
handleChange(e) {
if (e.target.checked) {
this.setState({
filteredFields: ['userEmail']
});
}
}
render() {
return(
<div>
<label>
<input type="checkbox" defaultChecked="true" value="userEmail"
onChange={this.handleChange.bind(this)}/>Email
</label>
<MeteorGriddle filteredFields={this.state.filteredFields}/>
</div>
);
}}