React - checkbox does not toggle - javascript

I am able to successfully change the discount amount from 0 to 50% off when the user checks the box off but it does not toggle off afterwards.
I'm assuming something is wrong with the handleChange function:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
// Define data above render()
constructor(){
super();
this.state = {
discount: 0,
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
discount: event.target.checked = this.state.discount = .50});
}
render() {
return(
<div>
Apply 50% discount:
<input type='checkbox' value={this.state.discount} checked={this.state.discount} checked={this.state.discount} onChange={this.handleChange} />
<br/><br/>);
}
}
export default App;

It looks like you're missing an = in your handleChange function, which is causing the state update to behave incorrectly.
Try revising this function like so, for clarity and correctness:
handleChange(event) {
// Toggle the discount value between 0.5 and 0.0 via this logic
const nextDiscount = (this.state.discount === 0.5) ? 0.0 : 0.5
// Update discount state with nextDiscount value
this.setState({ discount: nextDiscount });
}
Also, consider updating your render() method so that the value for the checked prop evaluates to truthy/falsey based on the value of this.state.discount (ie via this expression (this.state.discount === 0.5)). Also ensure that only one checked prop is passed to that checkbox input:
render() {
return(<div>
Apply 50% discount:
<input type='checkbox'
value={this.state.discount}
checked={ (this.state.discount === 0.5) }
onChange={this.handleChange} />
<br/>
<br/>);
}

Related

Troubles with state

I'm just started to learn react, and i have a question
Well, i can impact on state from one component to another. But can i do it in reverse?
Here's what i mean:
import React from 'react';
import Butt from './Button';
class Checkbox extends React.Component {
constructor(props) {
super();
}
render() {
return (
<div>
<Butt arg={13} />
</div>
);
}
}
export default Checkbox;
import React from 'react';
class Butt extends React.Component {
constructor(props) {
super();
this.state = {
s1: props.arg,
};
}
add = () => {
let val = this.state.s1;
val++;
this.setState({ s1: val });
};
render() {
return (
<div>
<label>
<label>
<button onClick={this.add}>add</button>
<div>{this.state.s1}</div>
</label>
</label>
</div>
);
}
}
export default Butt;
Sorry for my silly question. Thanks in advance :)
I am not sure about your question, but in react, there is a one-way flow (from parent to child) for transferring information (props, states, or ...). If you want to have access to states everywhere or set them in each direction you should use Redux or context or any other state management.
You're updating the Butt state from inside Butt so this will work fine. It won't change the value of this.props.arg though, if that's what you're asking.
Props are always non-mutable.
What you can do is have two components share the state of their parent...
class Parent extends React.Component {
state = {
val = 0
}
render () {
return (
<>
<Child1
val={this.state.val}
onChange={newVal => this.setState({ val: newVal })}
/>
<Child2
val={this.state.val}
onChange={newVal => this.setState({ val: newVal })}
/>
</>
)
}
}
Then inside the child components pass the updated value to onChange...
class Child1 extends React.Component {
handleChange() {
this.props.onChange(this.props.val + 1)
}
render() {
return (
<Button onClick={() => this.handleChange()}>
Update value
</Button>
)
}
}
This way you're just passing a new value from Child to Parent and letting Parent decide what to do with it.
Whether Child1 or Child2 sends the new value, both children will get updated when Parent calls this.setState({ val: newVal }) and changes this.state.val.

How to invoke child component function from parent component?

I have an input field component that meets these conditions:
Upon first focus, nothing happens until the field is valid, then a valid class is applied
Upon first blur, if the field is invalid, apply an invalid class.
After the first blur, upon any further engagement with the field, a class is applied whenever the value of the field changes from valid to invalid or vice versa.
To achieve this I have done this:
import React, { Component } from "react";
class Input extends Component {
constructor(props) {
super(props);
this.state = {
touched: false,
valid: false,
focused: false,
value: ""
};
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleFocus() {}
handleBlur() {
if (!this.state.touched) {
this.setState({
touched: true
});
} else if (this.state.touched) {
this.setState({
focused: true
});
}
}
handleChange(e) {
const val = e.target.value
this.setState({ value: val }, () => {
this.validateField();
}
);
}
validateField() {
const touched = this.state.touched;
const focused = this.state.focused;
const valid = this.state.valid;
const value = this.state.value;
if (value.length >= 5) {
this.setState({
valid: true,
touched: true
});
} else {
this.setState({ valid: false });
}
}
render() {
return (
<div>
<input
id={this.props.id}
name={this.props.name}
type="text"
className={`form-control ${styles["kyi-input"]} ${
this.state.valid ? "is-valid" : ""
} ${this.state.touched && !this.state.valid ? "is-invalid" : ""}`}
required
spellCheck="false"
autoComplete="off"
onFocus={this.handleFocus}
onChange={this.handleChange}
value={this.state.value}
onBlur={this.handleBlur}
placeholder={this.props.placeholder}
/>
</div>
);
}
}
class Parent extends Component {
handleInput(val, name) {
// Can get value of input here
this.setState({
[name]: val
});
}
render() {
<Input placeholder="Test" onChange={(val) => {this.handleInput(val, 'inputName')}}/>
}
}
<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>
It works, but this means that the state of the field lives in the child component and not the parent.
The input field's onBlur function is reliant on the state of the field.
Is there a way to refactor this so that the input state lives in the parent component while the onBlur function lives in the child component?
I think you should get all your State in the Parent component, you should also get all the functions that modify it in the Parent Component. This would allow you to have a 'single source of truth' that keeps track of state's changes and pass it to all your child components.
Check out Lifting state up

ReactJS: doing calculations to setState, and updating

I'd like to have two input numeric fields, value1 and value2 and add the values of those two fields. The sum will then be saved in this.state.sum. I also don't want to use a "submit" button. Some code:
import React, { Component } from 'react';
import addNumbers from "./components/addNumbers"
class App extends Component {
constructor() {
super()
this.state = {
value1: 10,
value2: 3,
sum: 13
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
//first setState call works fine
this.setState({[event.target.name]: event.target.value})
//call addNumbers function
const sum = addNumbers(this.state.value1, this.statevalue2)
//this second setState() call will lag by one step
this.setState({sum: sum})
console.log(newBarData)
}
render() {
return (
<div>
<form>
<input name="value1" type="number" placeholder="10" onBlur={this.handleChange} />
<input name="value2" type="number" placeholder="3" onBlur={this.handleChange} />
</form>
</div>
);
}
}
export default App;
What happens is: the second setState() call won't be effected until I make a second change on the page. This is quite a common issue, but I'm not sure how to work around it. I'd like for it to be able to proc immediately after the user updates the form. In the actual use-case, there'll be some calculations based on user-input values, then visualized on a graph (plotly.js), and I want to be able to update the graph "live" after each input field change.
You can use currying to create different handler in one piece of code (see: makeHandleChange). Then you can use componentDidUpdate to check if the value of your inputs changed to update your sum state value.
import React, { Component } from 'react';
import addNumbers from "./components/addNumbers"
class App extends Component {
state = {
value1: 10,
value2: 3,
sum: 13
}
componentDidUpdate(lastProps, lastState) {
const valueChanged = this.state.value1 !== lastState.value1 || this.state.value2 != lastState.value2
if (valueChanged) {
const sum = addNumbers(this.state.value1, this.state.value2)
this.setState({ sum })
}
}
makeHandleChange = id => ({ target: { value } }) => {
this.setState({
[`value${id}`]: value
})
}
render() {
return (
<div>
<form>
<input name="value1" type="number" placeholder="10" onBlur={this.makeHandleChange(1)} />
<input name="value2" type="number" placeholder="3" onBlur={this.makeHandleChange(2)} />
<div>the sum is: {this.state.sum}</div>
</form>
</div>
);
}
}
export default App;

How can i store the value of a React input element and use it in some other elements

I am facing a problem with React input element, in which i want to take the input value (which is a number) and multiply it with another number and show the value on a span element.
I am open for any solution or changes in my code
I have tried to use normal javaScript but it is not working at all with React. such as getElementByClass("className").value
Here is my code
class Counter extends Component {
constructor() {
super();
this.state = {
totalPrice: "Total Price:"
};
}
render() {
return (
<div className="counter">
<input type="number" />
<span> {this.state.totalPrice} </span>
</div>
);
}
}
You can achieve it by this:-
import React from 'react'
export default class YourComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
totalPrice: 0
}
}
handleChange(ev){
let totalPrice = ev.target.value * 10 // your number here i have taken 10 for example
this.setState({totalPrice:totalPrice})
}
render() {
return (
<div>
<input type="number" onChange={this.handleChange.bind(this)}/>
<span>Total Price: {this.state.totalPrice}</span>
</div>
)
}
}

React JS range slider - using an array for the value?

I'm wondering how you'd go about getting the value of an index in an array using an input[type="range"] in React, similar to this example?
What I'm trying to do is this: pass in a range of values and be able to print out those values by using the index of the array.
As you'll see from the example code below, I am initially rendering the value I want (in this case, 'Apples') but then when I use the slide it then starts rendering the index of the array, instead of the values.
Here's what I've got so far:
class RangeSlider extends React.Component {
// constructor
constructor(props) {
super(props);
this.state = {
value: props.value[0]
};
}
handleChange(event, index) {
const { value } = this.state;
this.setState({ value: event.target.value});
}
render() {
const { value } = this.state;
const { label } = this.props;
return (
<div className="mb4">
<label className="f4 mt0">
{label} <b className="fw7 pl1">{value}</b>
</label>
<input
className="w-100 appearance-none bg-transparent range-slider-thumb-custom"
type="range"
min={0}
max={this.props.value.length - 1}
step={1}
value={value}
onChange={this.handleChange.bind(this)}
/>
</div>
);
}
}
window.onload = () => {
ReactDOM.render(
<RangeSlider
label={"I would like some "}
value={["Apples", "Oranges", "Pears"]} />,
document.getElementById("main"));
};
Link to a Codepen.
The only problem you were having is that on initial load, your state object was set to access the value in the array correctly. However, everytime the handleChange method fires, it overwrites the state with just an integer, and thus does not do what you are expecting.
If you instead just set the "value" property in your state object to a default value of "0", you can just track the index, and change one more line in your code, and it should work just fine.
First change your state to look like this:
this.state = {
value: 0
};
Next, change to this inside your jsx body:
{label} <b className="fw7 pl1">{this.props.value[value]}</b>
This way, you are always going to print out a value, and not an integer to the screen. I think this results in you having to add far less code.
Working Codepen.
Here is the updated code
import React from 'react'
class Range extends React.Component {
// constructor
constructor(props) {
super(props)
this.state = {
value: 0
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({ value: this.props.value[event.target.value]})
}
render() {
const { value } = this.state
const { label } = this.props
return (
<div className="mb4">
<label className="f4 mt0">
{label} <b className="fw7 pl1">{value}</b>
</label>
<input
className="w-100 appearance-none bg-transparent range-slider-thumb-custom"
type="range"
min={0}
max={this.props.value.length - 1}
step={1}
onChange={this.handleChange}
/>
</div>
)
}
}
export default Range

Categories

Resources