I have a parent component App rendering a list of new restaurants from a child component InputForm.
I have a addedrestaurant state inside App and a handler to save the input from a callback props passed to the child component InputForm.
I have console.log the restaurant attribute in the InputForm component, it is always empty even if I have user input in the form and have handlers for change in the component.
class App extends React.Component {
constructor(props) {
super(props)
this.handlerestaurantclick = this.handlerestaurantclick.bind(this)
this.saveRating = this.saveRating.bind(this)
this.saveRestaurant = this.saveRestaurant.bind(this)
this.state = {
restaurants: restaurants,
addedrestaurants: [],
showcomponent: false,
restaurantClicked: -1,
}
}
saveRestaurant(restaurant) {
this.setState(
(prevState) => {
let resto = prevState.addedrestaurants;
resto.push(restaurant);
return { resto };
})
console.log("after:" + this.state.addedrestaurants)
}
render() {
return <Inputform onSave={this.saveRestaurant} />
}
}
class Inputform extends React.Component {
constructor(props) {
super(props);
this.handlechange = this.handlechange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.state = {
restaurant: Object.assign({}, Init_value),
error: {}
}
}
handlechange(e) {
const name = e.target.name;
const value = e.target.value;
this.setState((prevState) => {
prevState.restaurant[name] = value;
return { restaurant prevState.restaurant };
})
}
handleSave = (e) => {
this.props.onSave(this.state.restaurant);
this.setState({
restaurant: Object.assign({}, Init_value),
error: {}
})
e.preventDefault()
}
render() {
return (
<form className="inputform">
<div>
<h4>
Add new Restaurant
<FontAwesomeIcon icon={faBars} />
</h4>
</div>
<div className="inputcontainer ">
<input className="InputItem restaurant-name" type="text" name="restaurantName" placeholder="Name" value={this.state.restaurant.restaurantName} onChange={this.handlechange} />
</div>
<div className="inputcontainer adress">
<textarea className="InputItem" name="address" rows="4" cols="18" placeholder="Adress" value={this.state.restaurant.address} onChange={this.handlechange}>
</textarea>
</div>
<div className="inputcontainer rating">
Rating
<select >
<option> </option>
<option >0 </option>
<option >1</option>
<option>2</option>
<option>3</option>
<option>4</option><option>5</option>
</select>
</div>
<div className="inputcontainer">
<textarea className="InputItem" rows="4" cols="18" placeholder="comment"> </textarea>
</div>
<input className="inputitem submitbutton" type="submit" value="submit" onClick={this.handleSave} />
</form>
)
}
}
You made couple of mistakes. I have mention it in the below code as #cluemediator Fixed.
import React, { Component } from "react";
import { render } from "react-dom";
import Hello from "./Hello";
import "./style.css";
class App extends React.Component {
constructor(props) {
super(props)
// #cluemediator Fixed: Remove both line because method is not exist.
// this.handlerestaurantclick = this.handlerestaurantclick.bind(this)
// this.saveRating = this.saveRating.bind(this)
this.saveRestaurant = this.saveRestaurant.bind(this)
this.state = {
restaurants: [], // #cluemediator Fixed: remove "restaurants" because "restaurants" is not defined.
addedrestaurants: [],
showcomponent: false,
restaurantClicked: -1,
}
}
saveRestaurant(restaurant) {
this.setState(
(prevState) => {
let resto = prevState.addedrestaurants; resto.push(restaurant); return { resto };
})
console.log("after:" + this.state.addedrestaurants)
}
render() {
return <Inputform onSave={this.saveRestaurant} />
}
}
class Inputform extends React.Component {
constructor(props) {
super(props);
this.handlechange = this.handlechange.bind(this);
this.handleSave = this.handleSave.bind(this);
const Init_value = {}; // #cluemediator Fixed: define variable because it's used at below
this.state = {
restaurant: Object.assign({}, Init_value),
error: {}
}
}
handlechange(e) {
const name = e.target.name;
const value = e.target.value;
this.setState((prevState) => {
prevState.restaurant[name] = value;
return { restaurant: prevState.restaurant }; // #cluemediator Fixed: Add colon symbol
})
}
handleSave = (e) => {
this.props.onSave(this.state.restaurant);
this.setState({
restaurant: Object.assign({}, Init_value),
error: {}
})
e.preventDefault()
}
render() {
return (
<form className="inputform">
<div>
<h4>
Add new Restaurant
<FontAwesomeIcon icon={faBars} />
</h4>
</div>
<div className="inputcontainer ">
<input className="InputItem restaurant-name" type="text" name="restaurantName" placeholder="Name" value={this.state.restaurant.restaurantName} onChange={this.handlechange} />
</div>
<div className="inputcontainer adress">
<textarea className="InputItem" name="address" rows="4" cols="18" placeholder="Adress" value={this.state.restaurant.address} onChange={this.handlechange}>
</textarea>
</div>
<div className="inputcontainer rating">
Rating
<select >
<option> </option>
<option >0 </option>
<option >1</option>
<option>2</option>
<option>3</option>
<option>4</option><option>5</option>
</select>
</div>
<div className="inputcontainer">
<textarea className="InputItem" rows="4" cols="18" placeholder="comment"> </textarea>
</div>
<input className="inputitem submitbutton" type="submit" value="submit" onClick={this.handleSave} />
</form>
)
}
}
render(<App />, document.getElementById("root"));
Hope this will work for you!
Related
I am writing todo app. There are main files in my directory now:
App (rendering main page with header and buttons)
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { triggerText: 'Create a task' };
}
propTypes = {
triggerText: PropTypes.string.isRequired,
handleSubmit: PropTypes.object.isRequired,
};
render() {
const { triggerText } = this.state;
const { handleSubmit } = this.props;
return (
<div className="App">
<header className="App-header">
<h1>To Do List</h1>
<div id="tasksList">
<span className="tasks active">Tasks</span>
</div>
<div id="categoriesList">
<span className="categories">Categories</span>
</div>
<div>
<Container triggerText={triggerText} onSubmit={handleSubmit} /> // creates modal dialog and uses TodoForm
</div>
</header>
<div id="container" className="container">
<TodoBox tasks={[]}/>
</div>
</div>
);
}
}
TodoForm (create a form)
export default class TodoForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '', tasks: [] };
}
propTypes = {
handleSubmit: PropTypes.object.isRequired,
}
handleRemove = (currentTaskId) => (e) => {
e.preventDefault();
const { tasks } = this.state;
this.setState({ tasks: tasks.filter(({ id }) => id !== currentTaskId) });
};
handleChange = (e) => {
e.preventDefault();
this.setState({ value: e.target.value });
}
handleSubmit = (e) => {
e.preventDefault();
const { value, tasks } = this.state;
const newTask = { id: uniqueId(), text: value };
this.setState({ value: '', tasks: [newTask, ...tasks] });
}
render() {
const { value } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="text"><strong>Create a task</strong></label>
<input
type="text"
onChange={this.handleChange}
value={value}
required
className="form-control"
id="text"
placeholder="I am going..."
/>
</div>
<div className="form-group">
<button type="submit" className="form-control btn btn-primary">Add</button>
</div>
</form>
);
}
}
TodoBox (generating list of tasks)
class Item extends React.Component {
propTypes = {
onRemove: PropTypes.object.isRequired,
task: PropTypes.string.isRequired,
};
render() {
const { task, onRemove } = this.props;
return (
<div className="row">
<div>
<button type="button" className="btn btn-primary" onClick={onRemove}>-</button>
</div>
<div className="col-10">{task.text}</div>
</div>
);
}
}
export default class TodoBox extends React.Component {
constructor(props) {
super(props);
}
propTypes = {
tasks: PropTypes.string.isRequired,
}
render() {
const { tasks } = this.props;
return (
<div className="item">
{tasks.map((task) => (
<div key={task.id}>
<Item task={task} onRemove={this.handleRemove} />
<hr />
</div>
))}
</div>
);
}
}
And the question is: how I can pass the state from TodoForm to TodoBox in App (it is initialize as an empty array now). I want to output tasks at the bottom of the same page in container after header element.
You can create a function (addTodo) in App component and pass it down to the TodoForm component. In TodoForm component you can invoke the addTodo function from props and send the todoValue as arguments props.addTodo(todoValue). In addTodo function in App component you can update the todoValue to state. Once you update the state it will re-render the App component, then the TodoBox component will call with the updated todoValue value.
Note: But it is not best practice. The best practice is to use React Context
I am working on the library project. Users can add books to the library.
So, I have created the form to add a book. The form contains from the name, author, publisher, pages, ISBN and info fields. I have created the dropdown component for authors and publishers, so the user can choose from this component:
import AuthorsService from './AuthorsService'
const authorsService = new AuthorsService();
class AuthorsDropDown extends Component {
constructor(props) {
super(props);
this.state = {
authors: [],
};
}
componentDidMount() {
var self = this;
authorsService.getAuthors().then(function (result) {
self.setState({ authors: result});
});
}
render() {
return (
<div className="form-group col-sm-4">
<label>Author:</label>
<select className="form-control" onChange={(ev) => this.props.onChange(ev.target.value)}>
{this.state.authors.map( a =>
<option key={a.id} value={a.id}>{a.first_name + ' '+a.last_name }
</option>)
}
</select>
</div>
);
}
}
export default AuthorsDropDown;
I have assigned initial value for author.id and publisher.id fields in parent component as null, but, these fields only got their values after dropdown changes (i.e after onChange is fired). I have no idea how to set the value to them on rendering (i.e. initialization state). Here is the parent component:
import React, { Component } from "react";
import BookService from "./BooksService";
import AuthorsDropDown from "./AuthorsDropDown";
import PublishersDropDown from "./PublishersDropDown";
const bookService = new BookService();
class BookCreateUpdate extends Component {
constructor(props) {
super(props);
this.state = {
author:{id:null},
publisher:{id:null}
}
this.handleSubmit = this.handleSubmit.bind(this);
this.onChangeAuthor = this.onChangeAuthor.bind(this);
this.onChangePublisher = this.onChangePublisher.bind(this);
}
onChangeAuthor(new_author_id){
this.setState({author:{id:new_author_id}});
}
onChangePublisher(new_publisher_id){
this.setState({publisher:{id:new_publisher_id}});
}
handleCreate() {
alert(this.state.author.id);
bookService
.createBook({
name: this.refs.name.value,
author: this.state.author,
publisher: this.state.publisher,
page: this.refs.pages.value,
inventor_number: this.refs.inventor_number.value,
description: this.refs.description.value
})
.then(result => {
alert("The book is added!");
})
.catch(() => {
alert("Error!!");
});
}
handleUpdate(pk) {
bookService
.updateBook({
pk: pk,
name: this.refs.name.value,
author: this.refs.author,
publisher: this.refs.publisher,
pages: this.refs.pages.value,
description: this.refs.description.value
})
.then(result => {
console.log(result);
alert("Success");
})
.catch(() => {
alert("Error.");
});
}
handleSubmit(event) {
const {
match: { params }
} = this.props;
if (params && params.pk) {
this.handleUpdate(params.pk);
} else {
this.handleCreate();
}
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="row">
<div className="form-group col-sm-8">
<label>Name:</label>
<input
className="form-control"
type="text"
ref="name"/>
</div>
</div>
<div className="row">
<AuthorsDropDown onChange={this.onChangeAuthor}/>
<PublishersDropDown onChange={this.onChangePublisher}/>
</div>
<div className="row">
<div className="form-group col-sm-4">
<label>Pages:</label>
<input
className="form-control"
type="number"
ref="pages"/>
</div>
<div className="form-group col-sm-4">
<label>ISBN:</label>
<input
className="form-control"
type="text"
ref="inventor_number"/>
</div>
</div>
<div className="row">
<div className="form-group col-sm-4">
<label>Info:</label>
<textarea
className="form-control"
ref="description"/>
</div>
</div>
<input className="btn btn-primary" type="submit" value="ok"/>
</form>
);
}
}
export default BookCreateUpdate;
I think you should consider a different way of tackling this problem. If I understand your requirement this component both creates and updates books. In this case, the <BookCreateUpdate/> component should receive a property which is the target book. For creation, it should be an empty object. For an update, it should be the object to update.
I think the mentioned concern relates to when editing. I suppose that books are persisted somewhere. If a book is passed in edit mode then the initial value should be passed down to the child components (input, AuthorsDropDown, PublishersDropDown) from the parent (<BookCreateUpdate/>).
class BookCreateUpdate extends Component {
constructor(props) {
super(props);
this.state(this.props.book)
}
onInputChange = propName => (e) => {
this.setState({[propName]: e.target.value })
}
...
handleCreate() {
const bookDraft = this.state;
bookService
.createBook(bookDraft)
.then(result => {
alert("The book is added!");
})
.catch(() => {
alert("Error!!");
});
}
...
render(){
const bookDraft = this.state;
return (
...
<div className="row">
<div className="form-group col-sm-8">
<label>Name:</label>
<input
className="form-control"
type="text"
value = {bookDraft.name}
onChange={this.onInputChange('name')}
/>
</div>
</div>
<AuthorsDropDown onChange={this.onChangeAuthor} authorId = {bookDraft.authorId}/>
<PublishersDropDown onChange={this.onChangePublisher} publisherId = {bookDraft.publisherId}/>
....
)
}
}
BookCreateUpdate.propsTypes = {
book: PropTypes.object
}
BookCreateUpdate.defaultProp = {
book: {authorId: null, publisherId: null}
}
It is also best not to use refs in this case. It is cleaner to pass a value to input and pass a callback for onChange event.
In my code, I use a click event on the InterestBox in order to update the appearance of the InterestBox and to change the state of the parent of the parent of InterestBox.
However, when I inspect the element with the React Developer Tools or that I try to send a request to my API, the state.interests is always empty. But, when I log the state in the console, it shows an array with a length of 0, but containing all the proper values.
I tried to find what is wrong with my code, but I think I need an external look to find what is wrong.
import axios from 'axios';
import * as Cookies from 'js-cookie';
import React, { Component } from 'react';
import Button from '../../components/Button';
import Dashboard from '../Dashboard';
import ErrorContainer from '../../components/ErrorContainer';
import InterestList from '../../components/register/InterestList';
export class EditUser extends Component {
constructor(props) {
super(props);
this.state = {loading: true, interests: []}
this.addInterest = this.addInterest.bind(this);
this.logState = this.logState.bind(this);
}
addInterest(id, name) {
console.log('hoppity hippity you parenty')
var mid = 'm' + id;
console.log(this.state.interests[mid] == undefined)
if(this.state.interests[mid] == undefined) {
console.log(this.state);
this.setState((state) => {
state.interests[mid] = name;
return {interests: state.interests}
}, () => {
console.log(JSON.stringify(this.state.interests))
})
} else {
console.log('deleted')
var newInterest = this.state.interests;
delete newInterest[mid]
this.setState({interests: newInterest})
}
console.log(this.state.interests)
}
componentDidMount() {
var token = Cookies.get('token');
axios.get('http://localhost:8000/api/details', {headers: {"Accept": 'application/json', "Authorization": `Bearer ${token}`}}).then(
(success) => {
this.setState({
loading: false,
firstname : success.data.data.user.firstname,
lastname: success.data.data.user.lastname,
email: success.data.data.user.email,
dob: success.data.data.user.dob,
address: success.data.data.user.address,
uinterests: success.data.data.interests
})
}, (error) => {
this.props.history.push('/deconnexion');
}
)
var places = require('places.js');
var placesAutocomplete = places({
appId: "plZJLSHIW8M5",
apiKey: "0eddd2fc93b5429f5012ee49bcf8807a",
container: document.querySelector('#address-input')
});
}
logState() {
console.log(this.state);
}
render() {
return (
<Dashboard loading={this.state.loading}>
<h1 className="title">Modifier mon profil</h1>
<form className="user-form offer-update-form" onSubmit={this.handleSubmit}>
<label>Prénom :</label>
<input type="text" name="firstname" value={this.state.firstname} onChange={this.handleChange}></input> <br />
<label>Nom de famille :</label>
<input type="text" name="lastname" value={this.state.lastname} onChange={this.handleChange}></input> <br />
<label>Email :</label>
<input type="email" name="email" value={this.state.email} onChange={this.handleChange} /><br />
<label>Adresse :</label>
<input type="address" id="address-input" name="address" value={this.state.address} onChange={this.handleChange} /><br />
<label>Date de naissance :</label>
<input type="date" name="dob" value={this.state.dob} onChange={this.handleChange} /><br />
<InterestList alreadyChecked={this.state.uinterests} onClick={this.addInterest} />
<ErrorContainer errors={this.state.errors} />
<Button type="primary">Soumettre les changements</Button>
</form>
<Button type="danger" onClick={this.logState} />
</Dashboard>
)
}
}
export default EditUser
```
```
import React, { Component } from 'react'
import InterestBox from './InterestBox'
import Axios from 'axios'
export class InterestList extends Component {
constructor(props) {
super(props);
this.state = {pinterests: []}
this.pinterestRefs = React.createRef()
this.pinterestRefs.current = [];
}
componentDidMount() {
Axios.get('http://localhost:8000/api/interests')
.then((success) => {
this.setState({pinterests: success.data.data.interests});
})
}
componentDidUpdate(prevProps) {
console.log(JSON.stringify(prevProps));
console.log(JSON.stringify(this.props))
if(this.props.alreadyChecked != prevProps.alreadyChecked) {
this.props.alreadyChecked.forEach((item) => {
this.pinterestRefs.current.forEach((pinterest) => {
if(item == pinterest.props.id) {
console.log(pinterest)
pinterest.handleClick();
}
})
console.log(item)
})
}
console.log(this.pin)
}
render() {
return (
<React.Fragment>
{Object.keys(this.state.pinterests).map((interest, i) => {
var pinterest = this.state.pinterests[interest];
var callbackRef = node => this.pinterestRefs.current[i] = node;
return <InterestBox id={pinterest.id} onClick={this.props.onClick} icon={pinterest.picture_src} title={pinterest.name} ref={callbackRef} />
})}
</React.Fragment>
)
}
}
export default InterestList
```
```
import React, { Component } from 'react'
export class InterestBox extends Component {
constructor(props) {
super(props);
this.images = require('../../img/interests/*.svg');
this.state = {activated: false};
this.interest_box_content = React.createRef();
this.interest_text = React.createRef();
this.handleClick = this.handleClick.bind(this);
this.updateDimensions = this.updateDimensions.bind(this);
}
handleClick() {
console.log('hoppity hippity you clicky')
this.props.onClick(this.props.id, this.props.title);
this.setState(prevState => ({
activated: !prevState.activated
}))
}
updateDimensions() {
console.log((window.getComputedStyle(this.refs.interest_box_content).width))
this.refs.interest_text = (window.getComputedStyle(this.refs.interest_box_content).width)
}
render() {
return (
<div className="column is-one-fifth-desktop is-half-touch">
<div className="interest-box">
<div className="interest-box-adjuster">
<div ref={"interest_box_content"} className={"interest-box-content " + (this.state.activated == true ? 'interest-box-activated' : '')} onClick={this.handleClick}>
<img className="interest-icon" src={this.images[this.props.icon]} style={{'height': '50%'}}></img>
<i className="activated-icon fas fa-check"></i>
<span ref={"interest_text"} className="interest-text">{this.props.title}</span>
</div>
</div>
</div>
</div>
)
}
}
export default InterestBox
```
you have initialized interest as an array using []
but then, you are updating it as a map state.interests[mid] = name;
Note: JS is not type-safe. after the above statement, interests no longer remained an array
That's the reason why on console you are able to see it being populated but with an array length of 0. that's because you are outputting an object now and not an array.
i'm writing this today because i need help.
First of all, it’s not my code but an example of the Internet that fits my problem.
So i need to set the type of my input relative to my select.
For example, if i'm selecting Date, i want to have the type <input type="date" step="0.01" name="DL_m1" name="entrance" value={el.entrance ||''} onChange={this.handleChange2.bind(this, i)}/> and if i'm selecting another thing <input type="number" step="0.01" name="DL_m1" name="entrance" value={el.entrance ||''} onChange={this.handleChange2.bind(this, i)}/>
It is possible ? And if anyone can give me a lead on how to proceed.
export default class DynamicForm extends React.Component {
constructor(props) {
super(props);
this.state = initialState;
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit2 = this.handleSubmit2.bind(this);
}
addClick(){
this.setState(prevState => ({
users: [...prevState.users, { Name_initial: "", operator: "", entrance: "" }]
}))
}
createUI(){
return this.state.users.map((el, i) => (
<div key={i}>
<select name='formb_4' placeholder="First Name" name="Name_initial" value={el.Name_initial ||''} onChange={this.handleChange2.bind(this, i)} >
{['Date Cloture exercice N', 'Date Cloture exercice N-1', 'Date de création:', 'Durée Cloture exercice N', 'Durée Cloture exercice N-1', 'Date'].map((i,j)=>{
return <option key={i} value={i}>{i}</option>})}
</select>
{this.test15(el, i)}
<select name='formb_4' placeholder="First Name" name="operator" value={el.operator ||''} onChange={this.handleChange2.bind(this, i)} >
{['>', ">=", "==", '<', '<='].map((i,j)=>{
return <option key={i} value={i}>{i}</option>})}
</select>
<input type="number" step="0.01" name="DL_m1" name="entrance" value={el.entrance ||''} onChange={this.handleChange2.bind(this, i)}/>
<input type='button' value='remove' onClick={this.removeClick.bind(this, i)}/>
</div>
))
}
removeClick(i){
let users = [...this.state.users];
users.splice(i, 1);
this.setState({ users });
}
handleChange2(i, e) { const { name, value } = e.target;
let users = [...this.state.users];
users[i] = {...users[i], [name]: value};
this.setState({ users });
}
handleSubmit2(event) {
alert('A name was submitted: ' + JSON.stringify(this.state.users));
event.preventDefault();
}
handleChange(event) {
const InputValue = event.target.value;
const stateField = event.target.name;
this.setState({
[stateField]: InputValue,
});
console.log(this.state);
}
async handleSubmit(event) {
this.setState({ loading: true });
setTimeout(() => {
this.setState({ loading: false });
}, 2000);
event.preventDefault();
);
}
render() {
const { handleSubmit, handleChange} = this.props
return(
<div id="menu">
<div id="test">
<div id="normal"><label id="number">1</label><label id='title'>Date</label></div><br/>
<form onSubmit={this.handleSubmit2}>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
<input type="submit" value="Submit" />
</form>
</div>
</div>
)
}
}
Thanks you
With this, you can manage the types in the state. you can refactor it to fit your code.
class App extends Component {
constructor() {
this.state = {
inputType: 'text'
}
}
handleInputTypeChange = (e) => {
this.setState({...this.state, inputType: e.target.value})
}
render() {
return (
<>
<select id="inputType" onChange={this.handleInputTypeChange}>
<option value="text">Text</option>
<option value="date">Date</option>
<option value="email">Email</option>
<option value="number">Number</option>
</select>
{/* Input Text */}
<input type={this.state.inputType} />
</>
)
}
}
export default App
I'm a newbie to ReactJS and I have made an app where you can submit a name and email. The name and mail should be displayed in a list at the bottom of the page. It is displayed for a short period, but then the constructor gets called and clears the state and the list.
Why is the constructor called after the state change? I thought the constructor only runs once and then the render-method runs after setState() changes the state.
class App extends React.Component {
constructor(props) {
super(props);
console.log("App constructor");
this.state = {
signedUpPeople: []
};
this.signUp = this.signUp.bind(this);
}
signUp(person) {
this.setState({
signedUpPeople: this.state.signedUpPeople.concat(person)
});
}
render() {
return (
<div>
<SignUpForm signUp={this.signUp} />
<SignedUpList list={this.state.signedUpPeople} />
</div>
);
}
}
class SignUpForm extends React.Component {
constructor(props) {
super(props);
console.log("SignUpForm constructor");
this.state = {
name: "",
email: ""
};
this.changeValue = this.changeValue.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
changeValue(event) {
const value = event.target.value;
const name = event.target.name;
this.setState({
name: value
});
}
onSubmitForm() {
this.props.signUp(this.state);
this.setState({
name: "",
email: ""
});
}
render() {
console.log("SignUpForm render");
return (
<div>
<h2>Sign up</h2>
<form onSubmit={this.onSubmitForm}>
<label htmlFor="name">Name:</label>
<input id="name" name="name" onChange={this.changeValue} />
<br />
<label htmlFor="email">E-mail:</label>
<input id="email" name="name" onChange={this.changeValue} />
<input type="submit" value="Sign up" />
</form>
</div>
);
}
}
class SignedUpList extends React.Component {
render() {
console.log("SignedUpList render");
return (
<div>
<h2>Already signed up</h2>
<ul>
{this.props.list.map(({ name, email }, index) => (
<li key={index}>
{name}, {email}
</li>
))}
</ul>
</div>
);
}
}
ReactDOM.render(<App />, window.document.getElementById("app"));
See CodePen example
The default behavior of a form with input of type submit is to post back to the server.
<input> elements of type "submit" are rendered as buttons. When the
click event occurs (typically because the user clicked the button),
the user agent attempts to submit the form to the server.
You can pass the event object of the submit handler and use the event.preventDefault method to prevent the form from posting back:
onSubmitForm(e) {
e.preventDefault();
this.props.signUp(this.state);
this.setState({
name: "",
email: ""
});
}
Here is a running snippet of your code:
class App extends React.Component {
constructor(props) {
super(props);
console.log("App constructor");
this.state = {
signedUpPeople: []
};
this.signUp = this.signUp.bind(this);
}
signUp(person) {
this.setState({
signedUpPeople: this.state.signedUpPeople.concat(person)
});
}
render() {
return (
<div>
<SignUpForm signUp={this.signUp} />
<SignedUpList list={this.state.signedUpPeople} />
</div>
);
}
}
class SignUpForm extends React.Component {
constructor(props) {
super(props);
console.log("SignUpForm constructor");
this.state = {
name: "",
email: ""
};
this.changeValue = this.changeValue.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
changeValue(event) {
const value = event.target.value;
const name = event.target.name;
this.setState({
name: value
});
}
onSubmitForm(e) {
e.preventDefault();
this.props.signUp(this.state);
this.setState({
name: "",
email: ""
});
}
render() {
//console.log('SignUpForm render');
return (
<div>
<h2>Sign up</h2>
<form onSubmit={this.onSubmitForm}>
<label htmlFor="name">Name:</label>
<input id="name" name="name" onChange={this.changeValue} />
<br />
<label htmlFor="email">E-mail:</label>
<input id="email" name="name" onChange={this.changeValue} />
<input type="submit" value="Sign up" />
</form>
</div>
);
}
}
class SignedUpList extends React.Component {
render() {
//console.log('SignedUpList render');
return (
<div>
<h2>Already signed up</h2>
<ul>
{this.props.list.map(({ name, email }, index) => (
<li key={index}>
{name}, {email}
</li>
))}
</ul>
</div>
);
}
}
ReactDOM.render(<App />, window.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">
</div>
onSubmitForm(e) {
e.preventDefault(); // prevent the form from refreshing the page
this.props.signUp(this.state);
this.setState({
name: "",
email: ""
});
}
It is working with your codepen link :)
Have a deep look at this :
React - Preventing Form Submission
or
https://medium.com/#ericclemmons/react-event-preventdefault-78c28c950e46
Thank you all for your help! :-)
e.preventDefault();
Did fix the problem. Thanks!