I am new to reactjs and trying to implement simple todo app. But, upon submit I am not able to push into an array i.e a state variable.
Following is my code:
import React, { Component } from 'react';
class ToDo extends Component{
constructor(props){
super(props)
this.state={list:['hello'],item:''}
this.handleSubmit=this.handleSubmit.bind(this)
this.handleSearchChange=this.handleSearchChange.bind(this)
}
handleSubmit(e){
e.preventDefault();
this.setState(state=>({list:(state.list.push(this.state.item))}))
}
handleSearchChange(e){
this.setState({item:e.target.value})
}
render(){
console.log('state:',this.state.list)
let listing=this.state.list.map((item)=><li key={item}>{item}</li>)
return(
<div >
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>
<input className="form-control "type="text" value={this.state.item} onChange={this.handleSearchChange} />
</label>
<label>
<input type="submit" value="Submit" className="form-control" />
</label>
</div>
</form>
<ul>{listing}</ul>
</div>
)
}
}
export default ToDo;
When I try to click on submit it redirects to error.
Help would be appreciated.
Thanks.
try this:
handleSubmit(e){
const { list, item } = this.state
e.preventDefault();
this.setState({ list: [...list, item] })
}
Explaination: you can't mutate data, concatenate it like this instead.
Advice: use es6 functions always, so you will never need binding.
It's easy and helpful to you...
handleSubmit(e){
const {list, item}=this.state;
e.preventDefault();
this.setState({ list: [...list, item] });
}
Related
I am just making a simple app to learn react with redux.
I just want to get data input in the react input form on the server-side.
The problem is that the params on the server-side is like this.
{"item"=>{"name"=>"undefined","price"=>"undefined"...}...}
Here is part of my code:
import React from "react";
class ItemForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.update = this.update.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const ItemData = new FormData();
ItemData.append("item[name]", this.props.item.name);
ItemData.append("item[price]", this.props.item.price);
};
update(field) {
return (e) => {
this.setState({ [field]: e.target.value });
};
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<div>
<label>
<div>Item</div>
<input
type="text"
value={this.props.item.name}
onChange={this.update("name")}
/>
</label>
<label>
<div>Price</div>
<input
type="number"
value={this.props.item.price}
onChange={this.update("price")}
/>
</label>
<div>
<input type="submit" value="Submit" />
</div>
</div>
</form>
</div>
);
}
}
Shoule I use store function in redux or is there more easy way?
Thanks.
Assumption
I'm assuming that the problem is that the data you can access in your handleSubmit function is not being updated, therefore you always receive the values that you initialized the component with.
Solution
Initialize the state based on the name and price props passed in
Set the value of your input tags to the state values
Access the state in your handleSubmit function
import React from "react";
import { withRouter } from "react-router-dom";
class ItemForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.update = this.update.bind(this);
this.state = {
name: this.props.item.name,
price: this.props.item.price
}
}
handleSubmit(e) {
e.preventDefault();
const ItemData = new FormData();
ItemData.append("item[name]", this.state.name);
ItemData.append("item[price]", this.state.price);
};
update(field) {
return (e) => {
this.setState({ [field]: e.target.value });
};
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<div>
<label>
<div>Item</div>
<input
type="text"
value={this.state.name}
onChange={this.update("name")}
/>
</label>
<label>
<div>Price</div>
<input
type="number"
value={this.state.price}
onChange={this.update("price")}
/>
</label>
<div>
<input type="submit" value="Submit" />
</div>
</div>
</form>
</div>
);
}
}
export default withRouter(ItemForm);
Other suggestions
Your redux wrapper component doesn't have any big effects on this, so you can remove it from this question for clarity 😀
This is actually one of the benefits of redux, the connected component (ItemForm) is a regular React component and does not have any knowledge that it will be acted on by redux
Hope that helps! 👍
I'm learning to use react-redux, so sorry if I'm doing confusing!
I'm trying to create a form and insert data into the db.
Then I have created 2 page, one for the form and another one.
RequestForm
handleChange = (e) => {
let meeting = this.state.meeting;
meeting[e.target.name] = e.target.value;
this.setState({ meeting });
};
handleSubmit(event) {
event.preventDefault();
console.log(this.state.meeting);
this.props.addMeeting(this.state)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div>
<label>Motivation:</label>
<input
type="text"
name="motivation"
onChange={(event) => this.handleChange(event)}
/>
</div>
<div>
<label>Date:</label>
<input
type="date"
name="date"
onChange={(event) => this.handleChange(event)}
/>
</div>
MeetingRequest.js
import RequestForm from './RequestForm';
import { connect } from 'react-redux';
import {addMeeting} from '../Redux/actions';
class MeetingRequest extends Component {
render() {
const addMeeting = this.props
return (
<div>
<h2>Request Meeting</h2>
<RequestForm
addMeeting={addMeeting}
/>
</div>
);
}
}
function mapDispatchToProps(dispatch) {
return {
addMeeting: (meeting) => dispatch(addMeeting(meeting)),
};
}
export default connect(null, mapDispatchToProps)(MeetingRequest);
EDIT. Thank you to the comments the firt error is resolved, now I have a 500 problem. Could it be a problem about the Actions.js??
And also in your opinion is right how I'm trying to do??
Thank you
Change:
-const addMeeting = this.props
+const { addMeeting } = this.props
in MeetingRequest.js
Regarding your 500 error on API, it may be because you're sending JSON while setting multipart/form-data. Inspect using Network tab in dev tools.
If your backend need multipart/form-data you have to convert your state.meeting object to FormData
I want to append the pervious value of state with the current value of the input box
but when i use setState function its somehow not allowing to pass event as argument.
Problem:
setState(prev,props,e)
The 3rd argument (e) is not getting detected by setState function.
e.target.value is coming undefined
This is my code :
import React , {Component} from 'react'
class Todo extends Component{
constructor(){
super()
this.state={toDo:[],currentInput:"name"}
// bind the events
this.addItem=this.addItem.bind(this)
this.changeList=this.changeList.bind(this)
}
addItem(e){
// prevent default
e.preventDefault();
// this part is left
}
changeList(e){
this.setState(function (prev,props,e){
console.log(prev.currentInput)
return {currentInput:prev.currentInput+e.target.value} // this part is causing problem
})
}
render(){
return(
<div className="App">
<h1>Add your tasks</h1>
<form onSubmit={this.addItem}>
<input type="text" value={this.state.currentInput} onChange={this.changeList} ></input>
<input type="submit"></input>
</form>
<div className="List">
<h3>Remaining items:-</h3>
<ul>
</ul>
</div>
</div>
)
}
}
export default Todo
That's not how setState works, you can't pass additional arguments, if you pass a function, React will invoke it passing in the current state and the props as arguments
Worth mentioning that if you use a functional update you have to capture the input value before you call setState or call event.persist() as React will clear the event after the handler has been invoked setting event.target to null
Event polling
Example
changeList(e){
const { value } = e.target
// or call e.persist() and use e.target.value inside the function
// now it's safe to use a functional update
this.setState(prevState => ({
currentInput: prevState.currentInput + value
}))
}
You also don't want to append to the previous input state as e.target.value contains the full input value so you can just pass an object into setState
changeList(e){
this.setState({ currentInput: e.target.value })
}
you don't actually need to do prev.currentInput+e.target.value as e.target.value will be the current input value ... if you type alpha in input it will actually evaluate to namenamealpha whereas my guess is you are expecting namealpha
but if you still wanna make it work here is how you should do it
import React , {Component} from 'react'
class Todo extends Component{
constructor(){
super()
this.state={toDo:[],currentInput:"name"}
}
addItem = (e) => {
e.preventDefault();
}
changeList = (e) => {
const newValue = e.target.value;
this.setState((state) => {
console.log({state, newValue})
return({
currentInput: state.currentInput + newValue
})
});
}
render(){
return(
<div className="App">
<h1>Add your tasks</h1>
<form onSubmit={this.addItem}>
<input type="text" value={this.state.currentInput} onChange={this.changeList} ></input>
<input type="submit"></input>
</form>
<div className="List">
<h3>Remaining items:-</h3>
<ul>
</ul>
</div>
</div>
)
}
}
export default Todo
Alternatively and ideally you can also use hooks like this
import React , { useState }from 'react'
const Todo = () => {
const [currentInput, setCurrentInput] = useState('name');
return(
<div className="App">
<h1>Add your tasks</h1>
<form onSubmit={() => console.log('submit')}>
<input type="text" value={currentInput} onChange={(e) => setCurrentInput(e.target.value)} ></input>
<input type="submit"></input>
</form>
<div className="List">
<h3>Remaining items:-</h3>
<ul>
</ul>
</div>
</div>
)
}
export default Todo
The handleSubmit function seems to refresh the page without firing any of the internal logic. I've set up a few console.log's along the way to test out if the internally declared const that's set to the venue property in the state would log, but nothing appears.
I've commented on various parts of the function stepwise starting with setting the scheduling variable to my Firebase schedule table.
After that, I changed the handleSubmit function from an arrow function to just handleSubmit(e) (sorry, I'm new to this so I'm not familiar with the terminology)
import React, {Component} from 'react';
import FrontNav from './nav.js';
import firebase from '../Firebase';
class FrontSchedule extends Component {
constructor () {
super();
this.state = {
venue:'',
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange = (e) => {
e.preventDefault();
this.setState ({
venue: e.target.value,
});
}
handleSubmit = (e) => {
e.preventDefault();
// let schedule = firebase.database().ref('schedule')
const item = {
venue: this.state.venue,
}
console.log(item);
// schedule.push(item);
// console.log(firebase.database().ref('schedule'));
console.log(this.state.venue);
// this.setState({
// venue:'',
// })
}
render(){
return(
<div>
<FrontNav/>
<h1>Schedule</h1>
<form>
<input type="text"
name="venue"
onChange={this.handleChange}
onSubmit={this.handleSubmit}
value={this.state.venue}/>
<button onSubmit={this.handleSubmit}> Enter Event </button>
</form>
</div>
);
}
}
export default FrontSchedule;
Herein lies the crux of the problem. The page refreshes and the input bar clears, but no error message is provided. At this point, I'm really confused about what is going on here. Any feedback is appreciated!
Let us consider the following example:-
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
Now, when we press on submit button the default behavior to browse to a new page. If you want this behavior it works out of the box in ReactJS. But in cases where you need more sophisticated behavior like form validations, custom logic after the form is submitted you can use controlled components.
We can do so by using following:-
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
Now coming to your solution it can be implemented as follows:-
class FrontSchedule extends React.Component {
constructor () {
super();
this.state = {
venue:'',
}
/* this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this); */
}
handleChange = (e) => {
e.preventDefault();
this.setState ({
venue: e.target.value,
});
}
handleSubmit = (e) => {
event.preventDefault();
// let schedule = firebase.database().ref('schedule')
const item = {
venue: this.state.venue,
}
console.log(item);
// schedule.push(item);
// console.log(firebase.database().ref('schedule'));
console.log(this.state.venue);
// this.setState({
// venue:'',
// })
}
render(){
console.log(this.state);
return(
<div>
<h1>Schedule</h1>
<form onSubmit={this.handleSubmit}>
<input type="text"
name="venue"
onChange={this.handleChange}
onSubmit={this.handleSubmit}
value={this.state.venue}/>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
ReactDOM.render(<FrontSchedule />, document.querySelector("#app"))
Hope it helps :)
You can read more at react documentationhere
I am trying to create a customer details form in react (currently using react-json-form) where I can reuse the values in the inputs to create a saved file that the app can refer to. I have created the form and can output the results but I am unsure how to save the input values for future use or call them back once they are saved.
If anyone has any suggestions or examples of a form that does this then I would be greatly appreciative.
My code is as follows:
import React, { Component } from 'react';
import JSONTree from 'react-json-tree';
import { BasicForm as Form, Nest, createInput } from 'react-json-form';
const Input = createInput()(props => <input type="text" {...props} />);
const UserFields = () => (
<section>
<h3>User</h3>
<div>Name: <Input path="name" /></div>
<div>Email: <Input path="email" /></div>
</section>
);
export default class ExampleForm extends Component {
state = { data: {} };
updateData = data => this.setState({ data });
render() {
return (
<Form onSubmit={this.updateData}>
<Nest path="user">
<UserFields />
</Nest>
<button type="submit">Submit</button>
<JSONTree data={this.state.data} shouldExpandNode={() => true} />
</Form>
);
}
}
A more simple solution would be to use a form, like a semanti-ui-react form, store the information to the state onChange, then convert the info to JSON for storage.
import { Form, Button } from 'semantic-ui-react'
export default class App extends Component {
constructor() {
super()
this.state = {
name: "",
email: ""
}
}
handleChange = (e, {name, value}) => {
console.log(name, value)
this.setState({[name]: value})
}
render() {
return (
<div>
<Form onSubmit={this.sendDataSomewhere}>
<Form.Field>
<Form.Input name="name" value={this.state.name} onChange={this.handleChange}/>
</Form.Field>
<Form.Field>
<Form.Input name="email" value={this.state.email} onChange={this.handleChange}/>
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
</div>
)
}
}
I use a dynamic method of receiving the input from different fields using the name and val attributes. The values captured in state are then accessible by this.state.whatever
Hope this helped