Why my component is not changing state when I trigger the function - reactjs

I am in new in React and I am trying to change the state when the user type some values in the inout. For a reason the component does not seem to work. Could anyone explain me why I am not succeeding in implementing this function? Thanks, Valentino
import React, { Component } from 'react';
class Stake extends Component {
state = ({
userStake: null
});
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.value;
this.setState({
userStake: [...userStake, newStake]
})
}
render() {
return (
<div>
<form onSubmit={this.handleUserStake}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
required
/>
</form>
</div >
);
}
}
export default Stake;

to accomplish a controlled input you should add the property value pointing to the respective state, and onChange that will handle its state update. for your onSubmit you use another handler specific to it. you should also fix your handleChange to update its value correctly:
class Stake extends Component {
state = ({
userStake: [],
input: ''
});
handleUserStake = (e) => {
let input = e.target.value;
this.setState({ input });
}
handleSubmit = () => {
e.preventDefault();
let newStake = this.state.input;
this.setState({
userStake: [...this.state.userStake, newStake],
input: '',
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
value={this.state.input}
onChange={this.handleUserStake}
required
/>
</form>
</div>
);
}
}
export default Stake;

You need to first get userStake from the state
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.value;
// you need to first get it from the state before updating
const { userStake } = this.state;
this.setState({
userStake: [...userStake, newStake]
})
}

Firstly you should create constructor for your component with state and binded `handleUserStakez method.
Because you are waiting for the submit event from form you would use ref for the input:
this.inputRef = React.createRef();
ref={this.inputRef}
Full code here:
class Stake extends Component {
constructor(props) {
super(props);
this.state = {
userStake: ""
};
this.handleUserStake = this.handleUserStake.bind(this);
this.inputRef = React.createRef();
}
handleUserStake = (e) => {
e.preventDefault();
let newStake = this.inputRef.current.value;
console.log("newStake", newStake);
this.setState({
...this.state,
userStake: newStake
});
};
render() {
return (
<div>
STATE: {this.state.userStake}
<form onSubmit={this.handleUserStake}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
required
ref={this.inputRef}
/>
</form>
</div>
);
}
}

this should work ...
state = {
userStake: [],
};
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.stake.value;
this.setState((state) => ({
userStake: [...state.userStake, newStake],
}));
};
what was problem? :-
getting value you need to add NAME from target which is form to get field value. like ...
let newStake = e.target.stake.value;
getting current state value, your were just getting userStake out of nowhere so it was giving undefined error.
this.setState((state) => ({ userStake: [...state.userStake, newStake], }));
make default value to [] for userStake in state obj.
userStake: []

I think I found the solution. The problem was that I had to write [...this.state.userStake, newStake]

Related

Unable to change the value in the object

My objective is to change the value of the object to true or false while onchanging the checkbox.
Object contains:
{
id: '12497wewrf5144',
name: 'ABC',
isVisible: 'false'
}
Here is the code:
import React, { Component } from 'react'
class Demo extends Component {
constructor(props) {
super(props)
this.state = {
demo: {}
}
}
componentDidMount() {
axios
.get('/api/random')
.then(res => {
this.setState({ demo: res.data?.[0] })
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div>
<h1>{this.state.demo.name}</h1>
<input type="checkbox" value={this.state.demo.value} />
</div>
)
}
}
export default Demo
I don't know what to write in onchange method for checkbox to only change the value within the object.
Can anyone help me in this query?
<input
type="checkbox"
value={this.state.demo.value}
onChange={(event) => {
this.setState((prevState) => ({
...prevState,
demo: { ...prevState.demo, isVisible: event.target.checked }
}));
}}
/>
Given your state ends up looking like
this.state = {
demo: {
id: "12497wewrf5144",
name: "ABC",
isVisible: "false",
value: false
}
};
You can create a change handler as such
changeHandler = e => {
e.preventDefault();
const { checked } = e.target;
this.setState(prevState => ({
...prevState, // <-- spread existing state
demo: {
...prevState.demo, // <-- spread existing demo
value: checked, // <-- save the input's checked value
}
}))
}
Attach the changeHandler to the onChange event callback
<input
type="checkbox"
onChange={this.changeHandler}
value={this.state.demo.value}
/>
Ciao, you could use onClick event like this:
...
handleClick = (e, data) => {
const demo = { ...this.state.demo };
demo.isVisible = !demo.isVisible;
this.setState({ demo });
}
...
<input type="checkbox" value={this.state.demo.value} onClick={((e) => this.handleClick(e, data))}/>
...

React: how do I use onSubmit to change state?

I'm quite new to React, and have only completed a few projects with it. I'm currently trying to create a form that, using onSubmit, changes the state of "isSubmitted" from false to true. When "isSubmitted" is true, I'd like to render another component to show the results of the selection.
What's currently happening is that onChange is working and I can see the value of "selectedI" set as state in the console.log when I change it. However, when I click submit, this state of "isSubmitted" doesn't change.
My code is below. Any help is greatly appreciated!
import React, { Component } from "react";
import Results from "../components/Results";
export class Create extends Component {
constructor(props) {
super(props);
this.state = {
selectedI: { value: "" },
// selectedC: { value: "" },
// selectedG: { value: "" },
// selectedA: { value: "" },
isSubmitted: false,
};
}
handleChange = (event) => {
this.setState({
selectedI: { value: event.target.value },
});
};
handleSubmit = (event) => {
event.preventdefault();
this.setState({
isSubmitted: true,
});
};
render() {
console.log(this.state);
return (
<>
<form onSubmit={this.handleSubmit} onChange={this.handleChange}>
<select value={this.state.value}>
{this.props.ingredient.map((ingredient) => {
return (
<option value={ingredient.strIngredient1}>
{ingredient.strIngredient1}
</option>
);
})}
</select>
<input type="submit" value="Submit" />
</form>
{this.state.isSubmitted && <Results />}
</>
);
}
}
export default Create;
Inside your handleSubmit method correct the case on preventdefault. It should be preventDefault. Note the capital D. Once corrected it should stop your page from reloading and resetting your state along with it. See the code below.
handleSubmit = (event) => {
event.preventDefault();
this.setState({
isSubmitted: true,
});
};

Unable to update parent prop in react

I can insert the input value say "1,2,3" and when backspace it removes all but in the console "1" is still shown i.e., House{props{house{property{rent:1}}}}
I am providing the code here which has 3 files.
(1) house.js
import ValInput from "main/components/val-input";
class House extends Component {
state = {
rent:"",
};
componentDidMount() {
if (this.props.house.rent) {
const { rent} = this.props.house;
this.setState({ rent });
}
}
onChange = (e) => {
const rent = parseInt(e.target.value.replace(string);
this.setState({
rent,
});
};
render(){
const {house} = this.props;
const {rent} = this.state;
...
<ValInput
type="text"
value={ rent }
onChange={e => {
this.onChange(e);
}}
/>
}
(2) val-input\index.js
import React from "react";
import Input from "main/components/input";
const ValInput = props => (
<Input
{...props}
type={props.type ? props.type : "text"}
/>
);
export default valInput;
(3) components/input/index.js
import React from "react";
const noOp = () => {};
const Input = ({
onBlur = xP,
...otherProps
}) => (
<input
onBlur={e => {
e.target.placeholder = placeholder;
onBlur(e);
}}
{...otherProps}
/>
);
export default Input;
The expected result should be, after emptying the value say with backspace, and visit the page next time, the input field should be empty and should not show old value.
Check this CodeSandbox out I replicated your code and if I understood the problem right then fixed it
https://reactjs.org/docs/cross-origin-errors.html
For updating #NaderZouaoui, has given me an example how to do Call back :
1. Child file :
onChange={e => {
this.onChange(e);
}}
onChange = e => {
this.setState({
rent
});
this.props.callback(rent);
};
2. Parent file :
state = {
rent: ""
};
handleChangeRent = newRent => {
this.setState({ rent: newRent });
};
render(){
return(
<House house={{ rent }} callback={this.handleChangeRent} />
);
}

using Material-ui checkboxes with the reactjs and redux

I want to display the selected checkbox items, for which I'm using material-ui checkbox.
Right now I'm only able to display the items with checkboxes, but I am not able to display the selected items.
I know it is easy but I'm new to reactjs and redux so finding it difficult to start.
Hoping for a help.
Thank you.
this.state = {
data: [apple, kiwi, banana, lime, orange, grape],
}}
handleCheck(x) {
this.state.checkedValues.push(x);
}
render(){
{this.state.data.map((x) =>
<Checkbox
label={x} key={x.toString()}
onCheck={() => this.handleCheck(x)}
checked=true
}/>
)}}
Modifying the answer by #BravoZulu by adding the event as the argument in onChange() function.(Also note that use onChange() instead of onCheck() for material-UI checkboxes as shown in the official documentation). Also, don't forget to bind the function in the constructor. I hope this helps the community. Below is the code.
class App extends Component {
constructor(props) {
this.handleCheck = this.handleCheck.bind(this);
super(props);
this.state = {
data: [apple, kiwi, banana, lime, orange, grape],
checkedValues: []
}
}
handleCheck(e,x) {
this.setState(state => ({
checkedValues: state.checkedValues.includes(x)
? state.checkedValues.filter(c => c !== x)
: [...state.checkedValues, x]
}));
}
render() {
return (<div>
{ this.state.data.map(x =>
<Checkbox
label={x} key={x.toString()}
onChange={e => this.handleCheck(e,x)}
checked={this.state.checkedValues.includes(x)}
/>
)}}
</div>)
}
}
In the handleCheck function, you are attempting to update your component state incorrectly. You need to use setState to make changes to state. In your example, state isn't getting updated so that is probably why you aren't seeing anything get selected. Also, gonna help clean up your example a bit:
class CheckboxList extends React.Component{
constructor() {
super();
this.state = {
data: ['apple', 'kiwi', 'banana', 'lime', 'orange', 'grape'],
checkedValues: []
}
}
handleCheck(index) {
this.setState({
checkedValues: this.state.checkedValues.concat([index])
});
console.log(this.state.checkedValues.concat([index]))
}
render(){
const checks = this.state.data.map( (item, index) => {
return (
<span key={item}>
<input type="checkbox"
value={item}
onChange={this.handleCheck.bind(this, index)} //Use .bind to pass params to functions
checked={this.state.checkedValues.some( selected_index => index === selected_index )}
/>
<label>{item}</label>
</span>)
});
return <div>{checks}</div>
}
}
Update:
Added working jsfiddle.
A bit late to the party but here's a solution using a functional component and hooks
import React, { useState } from 'react';
import Checkbox from '#material-ui/core/Checkbox';
const App = ({ data }) => {
const [checked, setChecked] = useState([]);
const handleCheck = (event) => {
const { value } = event.target;
setChecked(checked.includes(value) ? checked.filter(c => c !== value) : [...checked, value]);
};
return (
<div>
{data.map(({ value }) => (
<Checkbox onChange={e => handleCheck(e)} checked {checked.includes(value)} />
))}
</div>
);
};
export default App;
In React, you shouldn't push data directly to your state. Instead, use the setState function.
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [apple, kiwi, banana, lime, orange, grape],
checkedValues: []
}
}
handleCheck(x) {
this.setState(state => ({
checkedValues: state.checkedValues.includes(x)
? state.checkedValues.filter(c => c !== x)
: [...state.checkedValues, x]
}));
}
render() {
return (<div>
{ this.state.data.map(x =>
<Checkbox
label={x} key={x.toString()}
onCheck={() => this.handleCheck(x)}
checked={this.state.checkedValues.includes(x)}
/>
)}}
</div>)
}
}
I was also stuck on this issue for quite some time when I finally found a fix to this. It never works for a functional component which returns a check box. I made a separate class component and wrapped it in Redux Field component and it worked perfectly. I really never understood why it didn't work for the fucntional component as it what is shown in their official example.
I have written the code that worked for me. Hope it helps :)
class CheckBoxInput extends React.Component {
onCheckBoxSelectChange = (input) =>
{
input.onChange();
this.props.onSelectChange();
}
render() {
const { label, input,} = this.props;
let name = input.name;
return (
<div>
<InputLabel htmlFor={label} style={{paddingTop: '15px'}}> {label} </InputLabel>
<FormControl {...input} >
<Checkbox
name = {name}
label = {label}
color= "primary"
checked={input.value ? true : false}
onChange={() => this.onCheckBoxSelectChange(input)}
/>
</FormControl>
</div>
)
}
}
const CheckBox = (props) => <Field component={CheckBoxInput} {...props} />;
export default CheckBox;
And to use this checkbox component:
<CheckBox name="isCurrent" label="Current" onSelectChange = {this.toggleCurrentEmployerSelection} />
In case you are working with objects instead of simple data types, here is a working approache:
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [{id: 1, name:'banana'},
{id: 2, name:'kiwi'}],
checkedValues: []
}
}
handleCheck(element) {
const values = this.state.checkedValues.filter(e => e.id === element.id).length > 0
? this.state.checkedValues.splice( this.state.checkedValues.findIndex( e => e.id === element.id),1)
: this.state.checkedValues.push(element);
this.setState({
checkedValues: values
});
}
render() {
return (<div>
{ this.state.data.map(el =>
<Checkbox
checked={this.state.checkedValues.filter(e => e.id === el.id).length > 0}
onChange={this.handleCheck.bind(this, el)} //Use .bind to pass params to functions
value={el}
/>
)}}
</div>)
}
}
So basically what the function handleCheck does is it checks whether the selected object is in the checkedValues array, if that is the case then it deletes it (case uncheck), otherwise it adds it (case check), is i add the checked object to the checkedValues array.
in the Checkbox checked checks whether there is an object in the checkedValues array that is equal to the current loop object, (case checked/unchecked)

React Geosuggest doesn't update state

i'm trying to make a weather app, and using external component 'react-geosuggest'.
My problem is, when I update the input (SEE:onChange={this.onInputChange}), that function doesn't take my input, and don't change the state, i.e I get undefined.
What's interesting, i've set initialvalue to be New York, and on submit I get results, without changing input information, so problem lies in updating input information and passing it to function handleOnSubmit.
I've read docs about that component, but couldn't figure it out, it has same values as simple , but something doesn't work.
Thanks!
class SearchBar extends Component {
constructor() {
super()
this.state = {city: 'New York'};
}
onInputChange = (e) => {
this.setState({city: e.target.value});
}
handleOnSubmit = (e) => {
e.preventDefault();
this.props.fetchWeather(this.state.city);
this.setState({city: ''});
}
render () {
return (
<div>
<form onSubmit={this.handleOnSubmit}>
<Geosuggest
initialValue={this.state.city}
onChange={this.onInputChange}
types={['(cities)']}
/>
<button type="submit">Search</button>
</form>
</div>
</div>
);
}
}
Bind the event on the constructor, set the value attribute in the render and remove the setState to empty string that you are doing in the handleOnSubmit event. I am afraid this last one is what it makes not working when you change the input.
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {city: 'New York'};
this.onInputChange = this.onInputChange.bind(this);
}
onInputChange = (city) => {
this.setState({city: city});
}
handleOnSubmit = (e) => {
e.preventDefault();
this.props.fetchWeather(this.state.city);
}
render () {
return (
<div>
<form onSubmit={this.handleOnSubmit}>
<Geosuggest
initialValue={this.state.city}
value={this.state.city}
onChange={this.onInputChange}
types={['(cities)']}
/>
<button type="submit">Search</button>
</form>
</div>
</div>
);
}
}
Use e.currentTarget.value instead. See this question for more on this.
Also try this:
onChange={this.onInputChange.bind(this)}
If you'd like to be more concise you can write it this way:
<Geosuggest
initialValue={this.state.city}
onChange={(e)=> this.setState({city: e.currentTarget.value})}
types={['(cities)']}
/>
You can also get the value of selected address using onSuggestSelect:
<Geosuggest
ref={el=>this._geoSuggest=el}
placeholder="Search for address"
onSuggestSelect={this.onSuggestSelect}
country='us'
/>
Then access the components like so:
onSuggestSelect(suggest) {
if (!suggest.gmaps) {
return;
}
const components = suggest.gmaps.address_components;
const address = {
street: this.findAddressComponent(components, 'street_number', 'short_name') + ' ' + this.findAddressComponent(components, 'route', 'short_name'),
city: this.findAddressComponent(components, 'locality', 'short_name'),
state: this.findAddressComponent(components, 'administrative_area_level_1', 'short_name'),
zip: this.findAddressComponent(components, 'postal_code', 'short_name'),
}
this.setState({
address
});
}
findAddressComponent(components, type, version) {
const address = components.find(function(component) {
return (component.types.indexOf(type) !== -1);
});
return address[version];
}

Resources