I'm trying to pass 2 elements within the todo array, however it just returns the term element value. I see no error in the console.
It seems that the
items: [...this.state.items, this.state.term, this.state.name ]
only accepts two parameters.
I'm currently following this
https://reactjs.org/docs/handling-events.html
const { Component } = React;
class App extends Component {
constructor(props) {
super(props);
this.state = {
term: '',
name: '',
items: []
};
}
onChange = (event) => {
this.setState({name: event.target.value, term: event.target.value});
}
onSubmit = (event) => {
event.preventDefault();
this.setState({
term: '',
name: '',
items: [
...this.state.items,
this.state.term,
this.state.name
]
});
}
render() {
return (
<div>
<form className="App" onSubmit={this.onSubmit}>
<input value={this.state.term} onChange={this.onChange}/>
<input value={this.state.name} onChange={this.onChange}/>
<button>Submit</button>
</form>
<pre>{JSON.stringify(this.state.items)}</pre>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<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>
<div id="root"></div>
I suspect the issue you're asking about is the fact that your onChange event updates both term and name and whatever you type into one input goes into the other. Here's how you can resolve that:
Add a name attribute to your input that corresponds to the key in the state.
Access the value of name in onChange and update the value accordingly.
Solution
const { Component } = React;
class App extends Component {
constructor(props) {
super(props);
this.state = {
term: '',
name: '',
items: []
};
}
onChange = (event) => {
const { name, value } = event.target;
this.setState({ [name]: value });
}
onSubmit = (event) => {
event.preventDefault();
this.setState({
term: '',
name: '',
items: [
...this.state.items,
this.state.term,
this.state.name
]
});
}
render() {
return (
<div>
<form className="App" onSubmit={this.onSubmit}>
<input name="term" value={this.state.term} onChange={this.onChange}/>
<input name="name" value={this.state.name} onChange={this.onChange}/>
<button>Submit</button>
</form>
<pre>{JSON.stringify(this.state.items)}</pre>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<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>
<div id="root"></div>
I dont think your this.setState has any issue for your example.
You seem to be using this.onChange wrong.
I changed its implementation so that both input can have their own respective handler.
onChange = key => event => {
this.setState({ [key]: event.target.value }); };
Also changed input callbacks to pass key value from the render function below.
render() {
const { term, name, items } = this.state;
return (
<div>
<form className="App" onSubmit={this.onSubmit}>
<input value={term} onChange={this.onChange('term')} />
<input value={name} onChange={this.onChange('name')} />
<button>Submit</button>
</form>
{items.join(", ")}
</div>
);
}
}
Your prior code was problematic which was rendering same value for name and term with whatever you type in any of your input boxes.
Related
i'm building basic chat app with react, and i had many of SO form submit questions and answers but none are helped me, i know it may be dumb type question but really i'm stucked here, any helps are thank you, below is my code.
export default class Call extends Component {
state = {
Message:''
};
onChange = e => {
let { Message, value } = e.target;
console.log(e.target.value); // here i'm getting input value
this.setState({ [Message]: value });
};
onSubmit = e => {
e.preventDefault();
console.log("Message is ", this.state.Message); //getting undefined
};
render() {
return (
<form onSubmit={this.onSubmit}>
<input type="text" name="Message" onChange={this.onChange}/>
<input type="submit" value="Send" />
</form>
)}
Try without brackets:
onChange = e => {
let { Message, value } = e.target;
console.log(e.target.value); // here i'm getting input value
this.setState({ Message: value });
};
You need to initialize state inside class constructor and set it using this.setState({ Message: value }) syntax.
class Call extends React.Component {
constructor(props) {
super(props);
this.state = {
Message: ''
};
}
onChange = e => {
let { value } = e.target;
console.log(e.target.value); // here i'm getting input value
this.setState({ Message: value });
};
onSubmit = e => {
e.preventDefault();
console.log("Message is ", this.state.Message); //getting undefined
};
render() {
return (
<form onSubmit={this.onSubmit}>
<input type="text" name="Message" onChange={this.onChange} />
<input type="submit" value="Send" />
</form>
);
}
}
ReactDOM.render(<Call />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
My first React session data storage, so thanks. I am trying to set up inputing data and then placing it in session storage, so it can be edited, viewed or deleted later. There are 2 pieces of data, "title" and "note" to be inputed into a form. Nothing happens when I type into the form inputs. Any other help welcome also.
class AddNote extends Component {
constructor(props) {
super(props);
this.state = {
title: '',
content: ''
}
}
componentDidMount() {
this.getFormData();
}
//let notes = getSessionItem(keys.notes);
//if (!notes) { notes = ""; }
onTitleChange(event) {
this.setState({ title: event.target.value }, this.storeFormData);
this.storeFormData();
}
onContentChange(event) {
this.setState({ content: event.target.value }, this.storeFormData);
}
storeFormData() {
const form = {
title: this.state.title,
content: this.state.content
}
setSessionItem(keys.user_form, form);
}
getFormData() {
const form = getSessionItem(keys.user_form);
if (form) {
this.setState({
title: form.name,
content: form.content
});
}
}
render() {
return (
<div>
<div>
<h2>ADD NOTE PAGE</h2>
</div>
<form classname="nav1">
<div>
<label><b>Title</b></label>
<input type="text"
value={this.state.title}
onchange={this.onTitleChange.bind(this)}
/>
</div>
<div>
<label><b>Content</b></label>
<input type="text"
value={this.state.content}
onchange={this.onContentChange.bind(this)}
/>
</div>
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default AddNote;
and the storage file:
export const keys = {
title: 'title',
notes: 'notes'
}
export const getSessionItem = function (key) {
let item = sessionStorage.getItem(key);
item = JSON.parse(item);
return item;
}
export const setSessionItem = function (key, value) {
value = JSON.stringify(value);
sessionStorage.setItem(key, value);
}
export const removeSessionItem = function (key) {
sessionStorage.removeItem(key);
}
No need to have 2 change handler for your input. You can do it using a common change handler.
<form classname="nav1">
<div>
<label><b>Title</b></label>
<input type="text"
value={this.state.title}
name="title" <---- Provide name here
onChange={this.onChange}
/>
</div>
<div>
<label><b>Content</b></label>
<input type="text"
value={this.state.content}
name="content" <---- Provide name here
onChange={this.onChange}
/>
</div>
<button type="submit">Submit</button>
</form>
Your onChange function should be, and use callback in setState to call your storeFormData function.
onChange = (e) => {
this.setState({
[e.target.name] : e.target.value
}, () => this.storeFormData())
}
Note: In React we use camelCase, for example, onchange should be onChange and classname should be className.
Also make sure you bind this to storeFormData and getFormData functions, or you can use arrow function's to automatically bind this.
Demo
Here the code https://codesandbox.io/s/yqxr2z02pv
I am using this code so i dont need setState one by one onUpdate
onUpdate = (event) => {
const { target: { name, value } } = event
console.log(value);
this.setState({ [name]: value })
}
But the component not show the value when input value changed.
Any simple example can made this working?
Instead of duplicating the state in the Parent and the Child you can keep the state just in the Parent component and pass them down as props. You could also put the name prop on your inputs and use the onUpdate prop directly to pass along the event.
Example
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
firstName: "firstName",
lastName: "lastName"
};
}
onUpdate = event => {
const {
target: { name, value }
} = event;
this.setState({ [name]: value });
};
render() {
const { firstName, lastName } = this.state;
return (
<div>
<h2>Parent</h2>
Value in Parent Component State firstName: {firstName}
<br />
Value in Parent Component State lastName: {lastName}
<br />
<Child
onUpdate={this.onUpdate}
firstName={firstName}
lastName={lastName}
/>
</div>
);
}
}
class Child extends React.Component {
render() {
const { firstName, lastName, onUpdate } = this.props;
return (
<div>
<h4>Child</h4>
first Name
<input
type="text"
placeholder="type here"
name="firstName"
onChange={onUpdate}
value={firstName}
/>
<br />
last Name
<input
type="text"
name="lastName"
placeholder="type here"
onChange={onUpdate}
value={lastName}
/>
</div>
);
}
}
ReactDOM.render(<Parent />, document.getElementById("root"));
<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>
<div id="root"></div>
Try making an object first and adding the dynamic key to that like so
onUpdate = (event) => {
const { target: { name, value } } = event
console.log(value);
const newData = {};
newData[name] = value;
this.setState(newData);
}
I edit your code. you can try.
https://codesandbox.io/s/m37wlryy78?fontsize=14
Child.js
import React from "react";
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
firstName: "",
lastName: ""
};
}
update = e => {
this.props.onUpdate(e);
this.setState({ [e.target.name]: e.target.value });
};
render() {
return (
<div>
<h4>Child</h4>
first Name
<input
type="text"
placeholder="type here"
onChange={this.update}
value={this.state.firstName}
name={"firstName"}
/>
<br />
last Name
<input
type="text"
placeholder="type here"
onChange={this.update}
value={this.state.lastName}
name={"lastName"}
/>
</div>
);
}
}
export default Child;
I want to change the input value according to state. The code below triggers the handleChange() method manually. This works for an input box, but I cannot figure out how to do this to also update a select box.
I tried the following but it didn't work.
ev = new Event("option", { bubbles: true });
el = ReactDOM.findDOMNode(node);
See full code below:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
value: "random text",
country: "USA"
}
}
handleChange (node, value ) {
if(typeof value === "object") {
this.setState({
country: value.target.value
});
} else {
this.setState({value: 'another random text'})
}
var event = new Event('input', { bubbles: true });
this.myinput.dispatchEvent(event);
}
render () {
return (
<div>
<input value={this.state.value} onChange={(e) => {this.handleChange(e)}} ref={(input)=> this.myinput = input}/>
<select onChange={(e) => {this.handleChange(e)}} name="country">
<option>USA</option>
<option>Mexico</option>
</select>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
Changes:
1. Define a name property same as state variable name with both the fields, input and select.
2. Bind the change function inside constructor:
this.handleChange = this.handleChange.bind(this);
3. Use [] to update the particular state variable in change function and access that state variable name by e.target.name.
4. You are using the controlled input element so ref is not required here, you can access input element value by this.state.value
Check the working snippet:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
value: "random text",
country: "USA"
}
this.handleChange = this.handleChange.bind(this);
}
handleChange (e ) {
this.setState({[e.target.name]: e.target.value})
}
render () {
return (
<div>
<input name='value' value={this.state.value} onChange={this.handleChange}/>
<select name="country" value={this.state.country} onChange={this.handleChange} >
<option>USA</option>
<option>Mexico</option>
</select>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
I'm trying to disable a button when an input field is empty. What is the best approach in React for this?
I'm doing something like the following:
<input ref="email"/>
<button disabled={!this.refs.email}>Let me in</button>
Is this correct?
It's not just duplication of the dynamic attribute, because I'm also curious about transferring/checking the data from one element to another.
You'll need to keep the current value of the input in state (or pass changes in its value up to a parent via a callback function, or sideways, or <your app's state management solution here> such that it eventually gets passed back into your component as a prop) so you can derive the disabled prop for the button.
Example using state:
<meta charset="UTF-8">
<script src="https://fb.me/react-0.13.3.js"></script>
<script src="https://fb.me/JSXTransformer-0.13.3.js"></script>
<div id="app"></div>
<script type="text/jsx;harmony=true">void function() { "use strict";
var App = React.createClass({
getInitialState() {
return {email: ''}
},
handleChange(e) {
this.setState({email: e.target.value})
},
render() {
return <div>
<input name="email" value={this.state.email} onChange={this.handleChange}/>
<button type="button" disabled={!this.state.email}>Button</button>
</div>
}
})
React.render(<App/>, document.getElementById('app'))
}()</script>
Using constants allows to combine multiple fields for verification:
class LoginFrm extends React.Component {
constructor() {
super();
this.state = {
email: '',
password: '',
};
}
handleEmailChange = (evt) => {
this.setState({ email: evt.target.value });
}
handlePasswordChange = (evt) => {
this.setState({ password: evt.target.value });
}
handleSubmit = () => {
const { email, password } = this.state;
alert(`Welcome ${email} password: ${password}`);
}
render() {
const { email, password } = this.state;
const enabled =
email.length > 0 &&
password.length > 0;
return (
<form onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="Email"
value={this.state.email}
onChange={this.handleEmailChange}
/>
<input
type="password"
placeholder="Password"
value={this.state.password}
onChange={this.handlePasswordChange}
/>
<button disabled={!enabled}>Login</button>
</form>
)
}
}
ReactDOM.render(<LoginFrm />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<body>
</body>
Another way to check is to inline the function, so that the condition will be checked on every render (every props and state change)
const isDisabled = () =>
// condition check
This works:
<button
type="button"
disabled={this.isDisabled()}
>
Let Me In
</button>
but this will not work:
<button
type="button"
disabled={this.isDisabled}
>
Let Me In
</button>
const Example = () => {
const [value, setValue] = React.useState("");
function handleChange(e) {
setValue(e.target.value);
}
return (
<input ref="email" value={value} onChange={handleChange}/>
<button disabled={!value}>Let me in</button>
);
}
export default Example;
<button disabled={false}>button WORKS</button>
<button disabled={true}>button DOES NOT work</button>
Now just use useState or any other condition to pass true/false into the button, assuming you are using React.
its simple let us assume you have made an state full class by extending Component which contains following
class DisableButton extends Components
{
constructor()
{
super();
// now set the initial state of button enable and disable to be false
this.state = {isEnable: false }
}
// this function checks the length and make button to be enable by updating the state
handleButtonEnable(event)
{
const value = this.target.value;
if(value.length > 0 )
{
// set the state of isEnable to be true to make the button to be enable
this.setState({isEnable : true})
}
}
// in render you having button and input
render()
{
return (
<div>
<input
placeholder={"ANY_PLACEHOLDER"}
onChange={this.handleChangePassword}
/>
<button
onClick ={this.someFunction}
disabled = {this.state.isEnable}
/>
<div/>
)
}
}