how to show a new user on the page? - reactjs

I'm a Junior. I could not find information on the Internet and could not solve it myself. I use for my app the react with axios. Through the post request I want to add a new user. How to show a new user on the page? not in the console.
import React from "react"; import axios from "axios";
class PersonInput extends React.Component {
state = {
name: '',
}
handleChange = (event) => {
this.setState({name: event.target.value});
}
handleSubmit = (event) => {
event.preventDefault();
const user = {
name: this.state.name
};
axios.post(`https://jsonplaceholder.typicode.com/users`, {user}).then((res) => {
console.log(res);
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
User Name:
<input type="text" name="name" onChange={this.handleChange} />
</label>
<button type="submit">Add user</button>
<ul>{this.state.res}</ul>
</form>
</div>
);
}
}
export default PersonInput;

You didn't need to make a post request for it.
Try this:
import React from "react"; import axios from "axios";
class PersonInput extends React.Component {
state = {
name: '',
users: ''
}
handleChange = (event) => {
this.setState({name: event.target.value});
}
handleSubmit = (event) => {
event.preventDefault();
this.setState({users: this.state.name});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
User Name:
<input type="text" name="name" onChange={this.handleChange} />
</label>
<button type="submit">Add user</button>
<ul>{this.state.users}</ul>
</form>
</div>
);
}
}
export default PersonInput;

Define a new key to your state and when u get response store it in that key
state = {
name: '',
res: []
}
onSubmit = async e => {
e.preventDefault();
const data = { name: this.state.name };
const response = await axios.post('https://jsonplaceholder.typicode.com/users', data);
this.setState({res: response.data});
}
And use async await it is easier and cleaner. Just a personal preference

Related

Cannot get input value on submit function

I am trying to display input value on submit. But it seems to be not working. I don't have any errors but nothing being rendered. What is wrong with the code?
import React from 'react';
import { Component } from 'react';
class App extends Component {
constructor (props) {
super(props)
this.state = {
city : ""
}
}
handleSubmit = (event)=> {
event.preventDefault();
this.setState ({
city : event.target.value
})
}
render () {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type = "text" city = "city_name" />
<button type="submit">Get Weather</button>
{this.state.city}
</form>
</div>
)
}
}
export default App;
<form
onSubmit={e=>{
e.preventDefault()
console.log(e.target[0].value)
}}>
<input type="text"/>
<button type="submit">dg</button>
</form>
that works for me very well
Remember onSubmit target:
Indicates where to display the response after submitting the form. So you can get inner elements (and their corresponding values) like normal javascript code.
const city = event.target.querySelector('input').value
handleSubmit = (event) => {
event.preventDefault();
this.setState ({ city })
}
I guess you want it to get work like below. But this is not the only way to get it done.
import React from "react";
import { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
city: ""
};
}
handleSubmit = (event) => {
const formData = new FormData(event.currentTarget);
event.preventDefault();
let formDataJson = {};
for (let [key, value] of formData.entries()) {
formDataJson[key] = value;
}
this.setState(formDataJson);
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type="text" name="city" />
<button type="submit">Get Weather</button>
{this.state.city}
</form>
</div>
);
}
}
export default App;
Code sandbox => https://codesandbox.io/s/eager-oskar-dbhhu?file=/src/App.js

How can I take a input from user and change it with setState?

constructor() {
super();
this.state = {
name: "",
name1: "",
};
}
change = () => {
this.setState({ name: this.state.name1 });
};
handleChange = (e) => {
this.setState({ name1: e.target.value });
};
render() {
return (
<div>
<input
type="text"
placeholder="Enter your name"
onChange={this.handleChange}
></input>
<button onClick={this.change}>Click Me!</button>
<h4>Hello! {this.state.name}</h4>
</div>
);
}
This is what I did but feels like it is nonsense on actual webpage even it works. Is there a better way to take input from user?
Why you need name and name1 in state. Just name should be fine. See the below code if that helps
I am not sure why you handle a event in button. May you can use a form with OnSubmit.
import React from "react";
import "./style.css";
export default class App extends React.Component {
constructor() {
super();
this.state = {
name: "",
};
}
render() {
return (
<div>
<input
type="text"
placeholder="Enter your name"
onChange={(e) => this.setState({name: e.target.value})}
/>
<button>Click Me!</button>
<h4>Hello! {this.state.name}</h4>
</div>
);
}
}
Your onChange in the input would be
onChange={event => this.handleChange(event)}
And for the button it would be
onChange{() => this.change()}
We would not require 2 states for the name but we would need one variable to store the name and second variable to let the component know that name has been update. We need the second variable because on button click only the name has to be updated(as per the code mentioned).The component would re-render when a state is updated. Below code might be helpful.
class Content extends React.Component {
constructor(){
super()
this.state = {
name: "",
}
this.name=''
}
change = () => {
this.setState({name: this.name})
}
handleChange = (e) => {
this.name=e.target.value
}
render(){
return(
<div>
<input type = "text" placeholder="Enter your name" onChange={this.handleChange}></input>
<button onClick={this.change}>Click Me!</button>
<h4>Hello! {this.state.name}</h4>
</div>
)
}}
Here is a version with React Hooks:
import React, { useState } from 'react';
export default function App() {
const [name, setName] = useState('');
const handleNameChange = (e) => {
const nameInput = e.target.value;
setName(nameInput);
};
return (
<div>
<input
type="text"
placeholder="Enter your name"
onChange={(e) => handleNameChange(e)}
></input>
<button>Click Me!</button>
<h4>Hello! {name}</h4>
</div>
);
}

When I submit the contact form its shows error in react js

When I submit the contact form its shows error like error sending message.
Please help me is there any mistake in my code. I am new in react js.
This is the code i have used. please help me is there any logical or syntax mistake in this.
import React, { FormEvent, ReactElement } from 'react';
import { noop } from 'rxjs';
import { EmailData } from '../../../models/i-email-data';
import { EmailInput, MessageInput, NameInput, SubjectInput } from './';
interface Props {
onSubmit: (data: EmailData) => Promise<any>;
}
*type* State = EmailData;
export class ContactForm extends React.Component<Props, State> {
public state: State = {
name: '',
email: '',
subject: '',
message: '',
};
public render(): ReactElement {
const { name, email, subject, message } = this.state;
return (
<>
<h3 className='contact-form__title'>Send a Message</h3>
<form className='form' onSubmit={this.onSubmit}>
<NameInput onChange={this.handleInputChange} value={name} />
<EmailInput onChange={this.handleInputChange} value={email} />
<SubjectInput onChange={this.handleInputChange} value={subject} />
<MessageInput onChange={this.handleInputChange} value={message} />
<div className='contact-form__btn-wrapper'>
<button className='contact-form__submit'> Submit</button>
</div>
</form>
</>
);
import React, { FormEvent, ReactElement } from 'react';
import { noop } from 'rxjs';
import { EmailData } from '../../../models/i-email-data';
import { EmailInput, MessageInput, NameInput, SubjectInput } from './';
interface Props {
onSubmit: (data: EmailData) => Promise<any>;
}
type State = EmailData;
export class ContactForm extends React.Component<Props, State> {
public state: State = {
name: '',
email: '',
subject: '',
message: '',
};
public render(): ReactElement {
const { name, email, subject, message } = this.state;
return (
<>
<h3 className='contact-form__title'>Send a Message</h3>
<form className='form' onSubmit={this.props.onSubmit}>
<NameInput onChange={this.handleInputChange} value={name} />
<EmailInput onChange={this.handleInputChange} value={email} />
<SubjectInput onChange={this.handleInputChange} value={subject} />
<MessageInput onChange={this.handleInputChange} value={message} />
<div className='contact-form__btn-wrapper'>
<button className='contact-form__submit'> Submit</button>
</div>
</form>
</>
);
}
private handleInputChange = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void => {
const { value, name } = event.target;
this.setState({ [name]: value } as any);
};
private onSubmit = async (e: FormEvent): Promise<void> => {
try {
e.preventDefault();
await this.props.onSubmit(this.state);
this.setState({ name: '', email: '', subject: '', message: '' });
} catch (e) {
noop();
}
};
This is the code i have used. please help me is there any logical or syntax mistake in this.
Based on your Props interface I guess you're passing an onSubmit callback as a prop.
If that's the case you need to extract onSubmit from this.props, so the following doesn't fail.
<form className='form' onSubmit={this.onSubmit}>
Edit 1: You need to pass your state in order to pass your form's state to the parent component
Change it to:
<form
className='form'
onSubmit={(event) => {
event.preventDefault();
this.props.onSubmit(this.state);
}}
>
Edit 2: I see you're missing handleInputChange as well.
A quick implementation of handleInputChange would look like this:
handleInputChange = (name) => ({ target }) => {
this.setState((prevState) => ({
...prevState,
[name]: target.value
});
}
And you could call it like so:
<NameInput onChange={this.handleInputChange('name')} value={name} />
<EmailInput onChange={this.handleInputChange('email')} value={email} />
there are a few issues with your code.
firstly you have no function called onSubmit so when you submit the form it's going to error coz it doesn't know this function.
<form className='form' onSubmit={this.onSubmit}>
you need to create a function like this:
onSubmit = () => {
// do stuff in here
}
there is also no function called: handleInputChange so you need to create this too, like so:
handleInputChange = () => {
// do stuff in here
}

Reactjs: Using same form for add and update

I crafted a reactjs crud app with help of a tutorial and it works great now. Now i am trying to merge two form together so that same form should be used for both add and update operation.
This is my allpost.js file
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Post from '../components/Post';
import EditComponent from '../components/editComponent';
class AllPost extends Component {
render() {
return (
<div>
<h1>All Posts</h1>
{this.props.posts.map((post) => (
<div key={post.id}>
{post.editing ? <EditComponent post={post} key={post.id} /> :
<Post key={post.id} post={post} />}
</div>
))}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
posts: state
}
}
export default connect(mapStateToProps)(AllPost);
and this is my postForm.js file:
import React, { Component } from 'react';
import { connect } from 'react-redux'
class PostForm extends Component {
handleSubmit = (e) => {
e.preventDefault();
const title = this.getTitle.value;
const message = this.getMessage.value;
const data = {
id: new Date(),
title,
message,
editing: false
}
console.log(data)
this.props.dispatch({
type: 'ADD_POST',
data,
});
this.getTitle.value = '';
this.getMessage.value = '';
}
render() {
return (
<div>
<h1>Create Post</h1>
<form onSubmit={this.handleSubmit}>
<input required type="text" ref={(input)=>this.getTitle = input}
placeholder="Enter Post Title"/>
<br /><br />
<textarea required rows="5" ref={(input)=>this.getMessage = input} cols="28"
placeholder="Enter Post" />
<br /><br />
<button>Post</button>
</form>
</div>
);
}
}
export default connect()(PostForm);
and this is my editComponent.js file
import React, { Component } from 'react';
import { connect } from 'react-redux';
class EditComponent extends Component {
handleEdit = (e) => {
e.preventDefault();
const newTitle = this.getTitle.value;
const newMessage = this.getMessage.value;
const data = {
newTitle,
newMessage
}
this.props.dispatch({ type: 'UPDATE', id: this.props.post.id, data: data })
}
render() {
return (
<div>
<form onSubmit={this.handleEdit}>
<input required type="text" ref={(input) => this.getTitle = input}
defaultValue={this.props.post.title} placeholder="Enter Post Title" /><br /><br />
<textarea required rows="5" ref={(input) => this.getMessage = input}
defaultValue={this.props.post.message} cols="28" placeholder="Enter Post" /><br /><br />
<button>Update</button>
</form>
</div>
);
}
}
export default connect()(EditComponent);
and this is my post.js file:
import React, { Component } from 'react';
import { connect } from 'react-redux'
class Post extends Component {
render() {
return (
<div>
<h2>{this.props.post.title}</h2>
<p>{this.props.post.message}</p>
<button onClick={() => this.props.dispatch({type: 'EDIT_POST', id: this.props.post.id})}>EDIT
</button>
<button onClick={ () => this.props.dispatch({type: 'DELETE_POST', id: this.props.post.id}) }>DELETE
</button>
</div>
);
}
}
export default connect()(Post);
and this is my postReducer.js file:
const postReducer = (state = [], action) => {
switch(action.type) {
case 'ADD_POST':
return state.concat([action.data]);
case 'DELETE_POST':
return state.filter((post)=>post.id !== action.id);
case 'EDIT_POST':
return state.map((post)=>post.id === action.id ? {...post,editing:!post.editing}:post)
case 'UPDATE':
return state.map((post)=>{
if(post.id === action.id) {
return {
...post,
title:action.data.newTitle,
message:action.data.newMessage,
editing: !post.editing
}
} else return post;
})
default:
return state;
}
}
export default postReducer;
Can anyone please help me to achieve this? I tried a lot to use same form form for both add and update and i failed to achieve this.
I think it's better you create separate component for rendering form data(FormComponent) and separate components for edit(EditComponent) and add(AddComponent).
This way there will not be clutter in one component and no if/else conditions for different modes like edit or add, or in future copy mode.
This approach will add flexibility and enhances compositional pattern of react.
1) AddComponent
import React, { Component } from 'react';
import { connect } from 'react-redux'
class AddComponent extends Component {
handleSubmit = (title, message) => {
const data = {
id: new Date(),
title,
message,
editing: false
}
this.props.dispatch({
type: 'ADD_POST',
data,
});
}
render() {
return (
<div>
<h1>Create Post</h1>
<FormComponent
buttonLabel='Post'
handleSubmit={this.handleSubmit}
/>
</div>
);
}
}
export default connect()(AddComponent);
2) EditComponent
import React, { Component } from 'react';
import { connect } from 'react-redux';
class EditComponent extends Component {
handleSubmit = (newTitle, newMessage) => {
const data = {
newTitle,
newMessage
}
this.props.dispatch({ type: 'UPDATE', id: this.props.post.id, data: data })
}
render() {
return (
<div>
<FormComponent
buttonLabel='Update'
handleSubmit={this.handleSubmit}
/>
</div>
);
}
}
export default connect()(EditComponent);
3) FormComponent
import React, { Component } from 'react';
class FormComponent extends Component {
handleSubmit = (e) => {
e.preventDefault();
const title = this.getTitle.value;
const message = this.getMessage.value;
this.props.handleSubmit(title, message);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input required type="text" ref={(input) => this.getTitle = input}
defaultValue={this.props.post.title} placeholder="Enter Post Title" /><br /><br />
<textarea required rows="5" ref={(input) => this.getMessage = input}
defaultValue={this.props.post.message} cols="28" placeholder="Enter Post" /><br /><br />
<button>{this.props.buttonLabel}</button>
</form>
);
}
}
export default FormComponent;
Hope that helps!!!
You can create your own Form component with a prop of editMode to control whether it's Create or Update.
import React, {Component} from 'react';
import PropTypes from 'prop-types';
class Form extends Component {
handleSubmit = e => {
e.preventDefault();
const {editMode, post} = this.props;
const title = this.titleRef.value;
const body = this.bodyRef.value;
if (editMode){
const data = {
title,
body
}
this.props.dispatch({type: 'UPDATE', id: post.id, data})
}
else {
const data = {
id: new Date(),
title,
message,
editing: false
}
this.props.dispatch({type: 'ADD_POST', data});
}
}
render() {
const {editMode, post} = this.props;
const pageTitle = editMode ? 'Edit Post' : 'Create Post';
const buttonTitle = editMode ? 'Update' : 'Post';
return (
<div>
<h1>{pageTitle}</h1>
<form onSubmit={this.handleSubmit}>
<input
required
type="text"
ref={input => this.titleRef = input}
placeholder="Enter Post Title"
defaultValue={post.title}
/>
<textarea
required
rows="5"
ref={input => this.bodyRef = input}
cols="28"
placeholder="Enter Post"
defaultValue={post.body}
/>
<button>{buttonTitle}</button>
</form>
</div>
);
}
}
Form.propTypes = {
editMode: PropTypes.bool,
post: PropTypes.object
}
Form.defaultProps = {
editMode: false, // false: Create mode, true: Edit mode
post: {
title: "",
body: ""
} // Pass defined Post object in create mode in order not to get undefined objects in 'defaultValue's of inputs.
}
export default Form;
It would be on create mode by default but if you wanna update the post you should pass editMode={true} to your form component.

How to get response data from ajax call in mapDispatchToProps

I'm working on a login system. When user input email and password and click submit I'm calling my endpoint to verify the credentials with mapDispatchToProps, if login is correct I update the app state with token and auth:true, otherwise I need to publish the error. How can I read the response error message (that coming from api backend json response)?
I'm looking to read the response of the dispatched usersLogin() function.
import React, { Component } from "react";
import { connect } from "react-redux";
import { usersLogin } from "../../actions/index";
import { Link } from "react-router-dom";
import i18n from "../../i18n";
function mapDispatchToProps(dispatch) {
return {
usersLogin: login => dispatch(usersLogin(login))
};
}
class ConnectedLoginForm extends Component {
constructor() {
super();
this.state = {
email: "",
password: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const { email } = this.state;
const { password } = this.state;
this.props.usersLogin({ email, password });
this.setState({ email: email, password: password });
}
render() {
const { email } = this.state;
const { password } = this.state;
console.log("this.props");
console.log(this.props.usersLogin);
return (
<form onSubmit={this.handleSubmit} className="login-form">
<div className="form-group">
<h2>{ i18n.t("Login") }</h2>
<input
type="text"
className="input-text"
id="email"
value={email}
onChange={this.handleChange}
placeholder="Email"
autoCorrect="off" autoCapitalize="none"
/>
<input
type="text"
className="input-text"
id="password"
value={password}
onChange={this.handleChange}
placeholder="Password"
autoCorrect="off" autoCapitalize="none"
/>
<button type="submit" className="button btn-primary">
Login
</button>
<div className="other-action">
<Link to="/logout">Registrati</Link>
<Link to="/logout">Password dimenticata</Link>
</div>
</div>
</form>
);
}
}
const Loginform = connect(null, mapDispatchToProps)(ConnectedLoginForm);
export default Loginform;
Sure, this is my login function, in a redux middleware:
const reqBody = { email: action.payload.email, password: action.payload.password };
const cfg = { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } };
axios.post(endpoint.users+'/login', qs.stringify(reqBody), cfg)
.then((result) => {
return dispatch({ type: "USERS_LOGIN_SUCCESS", payload : {token: result.data.token, auth: true } } );
})
.catch((err) => {
return dispatch({ type: "USERS_LOGIN_ERROR", payload : {token: '', auth: false } } );
})
Thank you everyone, I've changed my approach. I've installed react-toastify and I've putted the error notification in the catch block of the ajax call in the middleware.
.catch((err) => {
toast.error(i18n.t(err.response.data.errorMessage) );
return dispatch({ type: "USERS_LOGIN_ERROR", payload : { user : { token: '', auth: false } } } );
})
The solution seems to fit my need for now.

Resources