Redux-form to pass data by a POST request. - reactjs

I have to update my user's profile that has 5 fields name, bio address, image, and gender. I have created perfectly working API on Django that uses auth Knox token for authentication.
I have stored the auth token during login in the state. Of which the reducer looks like this:
case 'LOGIN_SUCCESSFUL':
case 'REGISTRATION_SUCCESSFUL':
localStorage.setItem("token", action.data.token);
return {...state, ...action.data, isAuthenticated: true, isLoading: false, errors: null};
I can access the token later on like this:
let headers = {"Content-Type": "application/json"};
let {token} = getState().auth;
if (token) {
headers["Authorization"] = `Token ${token}`;
}
My question is:
How can I make a form that takes this token as a header and makes a post request? What will be the reducers and what will be the actions?
class Profile extends Component {
constructor(props) {
super(props)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleSubmit(e) {
e.preventDefault()
console.log(this.props.Name)
}
change = e => {
console.log(e.target.name)
values.push(e.target.value)
[e.target.name]: e.target.value
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div>
<label htmlFor="Name">Name</label>
<input name="Name" onChange={e => this.change(e)} component="input" type="text" />
</div>
<div>
<label htmlFor="Bio">Bio</label>
<input name="Bio" component="input" onChange={e => this.change(e)} type="text" />
</div>
<div>
<label htmlFor="Address">Address</label>
<input name="Address" component="input" onChange={e => this.change(e)} type="text" />
</div>
<button type="submit">Submit</button>
</form>
)
}
}
const mapStateToProps = (state) => {
return {
profile: state.user,
}
}
const mapDiapatchToProps = (dispatch) => {
return {
updateprofile: (values) => dispatch(updateprofile(values))
}
}
export default connect(mapStateToProps, mapDiapatchToProps)(Profile);
I tried this but I got confused how to send values to action?
Or Should I have to use redux-form?
I want to make a put request on this API: api/update/profile/${id}
Please help me out.

You need to use an external library to make a HTTP call, like Axios.
In your action file you need to create the function updateProfile. Inside this function you need to make the HTTP call using Axios, or wathever you want. With axios your function will be something like this:
function updateProfile() {
return (dispatch) => {
axios({
method:'get',
url:'[YOUR API ADDRESS]',
headers: {Authorization: '[YOUR TOKEN]'},
data: {
name: 'bruce',
lastName: 'bane'
}
}).then(function(response) {
dispatch({
type: UPDATE_PROFILE,
payload: response
});
});
return null
}
}
In youe Profile component you need to change the mapDispatchToProps function to call the updateProfile function from the action file, like this:
const mapDispatchToProps = (dispatch) => {
return {
updateprofile: (values) => dispatch(profileActions.updateprofile(values))
}
}
Note: I didn't tested this code, but it will be something close to this. Hope it could help.

Related

FormData not working with Axios Post request - MERN react Js

I've been trying to make a post request to my server(Node Js+Mongodb which runs on localhost too). Axios.post works properly on the client code, however when i try to use formData it doesn't. I can't seem to find any reason why it's not working.
It leaves no error on the console(which makes it more frustrating).
Here is the client code:
someone pls point me to what I might be doing wrong.
import React, { useState } from 'react'
import Axios from 'axios'
export default function InputData() {
const [inputName, setInputName] = useState("")
const [inputAge, setInputAge] = useState(0)
const [inputEmail, setInputEmail] = useState("")
const [userImage, setUserImage] = useState("")
const [info,setInfo] = useState("")
var bodyFormData = new FormData();
bodyFormData.append('name', inputName);
bodyFormData.append('age', inputAge);
bodyFormData.append("email", inputEmail)
const createUser = () => {
Axios.post("http://localhost:3008/createUser",
bodyFormData , { headers: { 'Content-Type': 'multipart/form-data' } }).then(function (response) {
//handle success
console.log(response);
}).catch(function (response) {
//handle error
console.log(response);
});
}
return (
<div>
<form onSubmit={createUser} encType="multipart/form-data">
<div>
<input type="text" placeholder='enter name' value={inputName} width={400} onChange={(e) => setInputName(e.target.value)} /><br/>
<input type="number" placeholder='enter age' width={400} value={inputAge} onChange={(e) => setInputAge(e.target.value)} /><br/>
<input type="email" placeholder='enter e-mail' width={400} value={inputEmail} onChange={(e) => setInputEmail(e.target.value)} /><br />
<button>Submit</button>
</div>
</form>
</div>
)
}
axios: "^0.27.2",
react: "^18.2.0"
Couple of points:
You're probably not seeing any errors (output) in the console because you're submitting the form. You can change your onSubmit handler to include preventDefault:
const createUser = (e) => {
Axios.post("http://localhost:3000/createUser", bodyFormData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(console.log)
.catch(console.error);
e.preventDefault();
}
You can also keep it as is and see the previous output by persisting the logs of your browse across requests, in Firefox this checkbox:
You should add method=post to your form
I think you will receive all the data from the event [createUser method] on submitting the form, Try removing the header If you still have problem try as below, If you still have the problem check the server side Post method Params
let data = { name: inputName, age: inputAge, email: inputEmail }
Axios.post("http://localhost:3008/createUser",data )
.then(function (response) { console.log(response); })
.catch(function (response) { console.log(response); });

Unable to render output of an API call made from a text field unto the UI

pls am currently building a simple UI using react on codesandbox. I just want the user to be able to enter an API end point in a text field and have the output(response data) rendered on a text area. Below is my codesandbox project link:
https://codesandbox.io/s/dry-surf-6ygc5?file=/src/components/PostList.jsx. Your input will be highly appreciated!
It seems like your missed to the target value of input text in the OnChange event for the Input. Please see the below code if that helps.
<input
name="inputApi"
onChange={(e) => this.setState({ apiText: e.target.value })}
type="text"
/>
I have removed few of your code. Also i didn't do other functionality like error handling. Please add a try catch block to Async block
submitHandler = async (e) => {
e.preventDefault();
try {
const resp = await axios.get(
`https://jsonplaceholder.typicode.com/${this.state.apiText}`
);
// console.log(resp.data);
this.setState({ posts: resp.data });
} catch (error) {
this.setState({ errorMsg: error.message });
}
};
Full code is here below.
import React, { Component } from "react";
import axios from "axios"; //for making API calls
class PostList extends Component {
constructor(props) {
super(props);
/**
* the lines below are unneccessary
* as the functions are arrow functions
* and require no binding
* value={this.state.api}
*/
this.state = {
posts: [],
errorMsg: "",
api: {},
apiText: ""
};
} //end of constructor
submitHandler = async (e) => {
e.preventDefault();
try {
const resp = await axios.get(
`https://jsonplaceholder.typicode.com/${this.state.apiText}`
);
// console.log(resp.data);
this.setState({ posts: resp.data });
} catch (error) {
this.setState({ errorMsg: error.message });
}
};
render() {
const { posts, errorMsg } = this.state; //destructure the state object
//console.log(res.data);
return (
<div>
<form onSubmit={this.submitHandler}>
<input
name="inputApi"
onChange={(e) => this.setState({ apiText: e.target.value })}
type="text"
/>
<input type="submit" />
</form>
List of Posts: {posts.length}
{posts.length ? (
<div>
<textarea value={this.state.posts[0].title} readOnly />
</div>
) : null}
{errorMsg ? <div>{errorMsg}</div> : null}
</div>
); //endOfReturn
} //endOfRender
} //endOfPostList
export default PostList;
/**posts.map((post) => <div key={post.id}>{post.title}</div>)*/
You have a small error getting the value in your submitHandler.
Instead of the user input value, you pass the string "e.target.value", which is not true.
const resp = axios.get("e.target.value");
Use it like this instead
const inputLink = e.target[0].value;
const resp = axios.get(inputLink);
It also makes no sense to store the result of calling the axios.get function in the component state.
Immediately after the call, you can use then and catch on the result of calling axios.get
axios
.get(inputLink)
.then((res) => {
this.setState({ posts: res.data });
})
.catch((error) => {
this.setState({
errorMsg: "error retrieving data"
});
});
Thus, a minimal working component will look something like this.

React axios post request does not send the data

I am using react for my app. I am learning post request. I found one dummy api site Mocky where I can test my post request. This is my api link .For post request I used axios. I don't know how the Mocky api works. I made post request. when I console log the input values I can the value.But when I console log the response it seems like it does not get the data. I don't see any where I am making mistake.
Here is my code:
import React, { useState } from 'react';
import { API_URLS } from '../utilities';
import axios from "axios";
export default function CreateAccount() {
const [state, setState] = useState({
"email": ``,
"password": ``,
"loading": false,
"error": ``
});
const onChangeStudent = (e) => {
setState({
...state,
[e.target.id]: e.target.value
});
};
const onSubmit = async (e) => {
e.preventDefault();
console.log(state);
const url = `https://run.mocky.io/v3/15c2b7ec-9f31-4a18-ae60-a7f41e1f39b2`;
const obj = {
"email": state.email,
"password": state.password
};
console.log(obj.email); //I can see the input value
console.log(obj.password);//I can see the input value
axios
.post(url, obj)
.then((res) => {
console.log(res.data); // it does not show the data
console.log(res);
})
.catch((error) => {
setState({
...state,
"error": error
});
});
};
return (
<div>
<form onSubmit={onSubmit}>
<input
type="text"
value={state.name}
onChange={onChangeStudent}
id="email"
required
/>
<input
type="password"
value={state.password}
onChange={onChangeStudent}
id="password"
required
/>
<button
className="btn waves-effect blue lighten-1"
type="submit"
name="action"
disabled={state.loading}
>
{state.loading ? `loading...` : `save`}
</button>
</form>
</div>
);
}
Hi can't seem to find anything wrong with what you are doing.
I tested the below and it worked for me. Try to change from .then to await. Hope this solves your problem. Check in your network tab if your request is successful and if you are sending the body.
try {
const response = await axios.post('https://run.mocky.io/v3/4b95050f-2bcc-4c78-b86e-6cac09372dce', data);
console.log("Response", response);
} catch(e) {
console.error(e);
}

Firebase, React: How do I display http errors on client side?

I'm building a project with React and Firebase. I've split it into two repos - a backend repo for firebase functions, and a client-side repo for React. Part of my project involves user registration, and I want to be able to send any errors (eg, email already in use, weak password) to the client side, but I'm not sure how. Does anyone have suggestions about how I can pass backend errors to the client?
I know that I could move the firebase API call to client side which would make error handling much easier, but this would create complications.
Code as follows:
Registration component VenueRegister
import React from 'react'
import Header from './Header'
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button'
import axios from 'axios'
import { auth } from 'firebase/app'
class VenueRegister extends React.Component {
constructor() {
super();
this.state = {
email: '',
password:'',
confirmPassword:'',
venueName:'',
venueAddress:''
};
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(e){
this.setState({
[e.target.name]: e.target.value
})
}
handleSubmit(e) {
console.log("submit function reached");
e.preventDefault();
const venueData = {
email: this.state.email,
password: this.state.password,
confirmPassword: this.state.confirmPassword,
venueName: this.state.venueName,
venueAddress: this.state.venueAddress
};
axios("http://localhost:5000/gig-fort/us-central1/api/registerVenue", {
method: "POST",
headers: {
"content-type": "application/json",
},
data: venueData,
})
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.error(err);
});
}
render() {
return (
<>
<Header />
<h1 className="heading-venue-reg">Register your venue</h1>
<form onSubmit = {this.handleSubmit}>
<TextField
required
id="standard-required"
name = 'email'
label="Required"
defaultValue="email"
placeholder="email"
onChange = {this.handleChange}
/>
<TextField
required
id="standard-required"
name = 'password'
label="Required"
defaultValue="password"
placeholder="password"
onChange = {this.handleChange}
/>
<TextField
required
id="standard-required"
name = 'confirmPassword'
label="Required"
defaultValue="confirm password"
placeholder="confirm password"
onChange = {this.handleChange}
/>
<TextField
required
id="standard-required"
name = 'venueName'
label="Required"
defaultValue="venue name"
placeholder="venue name"
onChange = {this.handleChange}
/>
<TextField
required
id="standard-required"
name = 'venueAddress'
label="Required"
defaultValue="venue address"
placeholder="venue address"
onChange = {this.handleChange}
/>
<Button type="submit">Submit</Button>
</form>
</>
);
}
}
export default VenueRegister
Backend function for venue registration:
app.post('/registerVenue',(req,res) =>{
const newVenue = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
venueName: req.body.venueName,
venueAddress: req.body.venueAddress
}
let errors = {}
if(isEmpty(newVenue.email)){
errors.email = 'Email must not be empty'
}else if (!isEmail(newVenue.email)){
errors.email = 'must be a valid email address'
}
if(Object.keys(errors).length >0){
return res.status(400).json(errors)
}
let token, userId
db.doc(`/user/${newVenue.venueName}`).get()
.then(doc => {
if(doc.exists){
return res.status(400).json({venueName: `This venue name is already taken`})
} else {
return firebase
.auth()
.createUserWithEmailAndPassword(newVenue.email, newVenue.password)
}
})
.then(data=> {
userId = data.user.uid;
return data.user.getIdToken()
})
.then(idToken => {
token = idToken
const venueDetails ={
email: newVenue.email,
venueName: newVenue.venueName,
venueAddress: newVenue.venueAddress,
createdAt: new Date().toISOString(),
userId
}
return db.doc(`/users/${newVenue.venueName}`).set(venueDetails)
})
.then(() => {
return res.status(201).json({token})
})
.catch(err => {
console.error(err)
if(err.code === 'auth/email-already-in-use'){
return res.status(400).json({email: 'Email is already in use'})
} else {
return res.status(500).json({error:err.code})
}
//TODO: put in conditional statement that sends 'weak password error' to client
})
})
In the frontend, when receiving the data from the backend, you should check your response data for errors. It is very likely you would want a util function for that since it is a common task across almost all requests (hence re-utilize).
So you would like to check the response.status and then set a new state like a hasError or something that will cause a re-render to your component and show, i.e, a child component that displays the error to the user and gives the ability to retry the operation.

How to handle Log in errors through Redux in React application

I am learning React-Redux and trying to get more comfortable with it by implementing things in various ways. I have a login form where I want to display an error message if the username/password is invalid. I have created config file with the required user details. I am calling an authenticate api to generate a JWT token for the logged in user.So, the token you get as response of the authenticate api will have the logged in user details. I have done something like below but I see I am able to successfully login every time and not able to display any error message when I try to provide any random/wrong user name. I have commented out the componetWillreceiveProps function now but would like to understand what I am doing wrong.
My Log in Comp-
import React from "react";
import Header from "./header";
import Footer from "./footer";
import { connect } from "react-redux";
import { createLogIn, setAuthError } from "../actions/action";
const axios = require("axios");
import jwtdata from "../config/jwtdata";
class Login extends React.Component {
constructor() {
super();
this.state = {
account: { user: "", password: "" }
};
}
handleAccountChange = ({ target: input }) => {
const account = { ...this.state.account };
account[input.name] = input.value;
this.setState({ account });
};
handleLoginForm = e => {
e.preventDefault();
let postLoginData = {};
const userName = this.state.account.user;
// call to action
this.props.dispatch(createLogIn(postLoginData, userName));
this.props.dispatch(setAuthError())
this.props.history.push("/intro");
};
// componentWillReceiveProps(nextProps) {
// if (nextProps.authStatus){
// this.props.history.push("/intro");
// }
// }
render() {
const { account } = this.state;
return (
<div className="intro">
<Header />
<form onSubmit={this.handleLoginForm}>
<div className="content container">
<div className="profile" />
<div className="row">
<div className="col-xs-12">
<input
type="text"
autoFocus
placeholder="username"
name="user"
value={account.user}
onChange={this.handleAccountChange}
/>
<input
type="password"
placeholder="password"
name="password"
value={account.password}
onChange={this.handleAccountChange}
/>
<button
className={
"loginButton " +
(account.user && account.password
? "not-disabled"
: "disabled")
}
disabled={!account.user && !account.password ? true : false}
>
<span>Sign in</span>
</button>
</div>
{!this.props.authStatus ? (
<p className="login-error">
Authorization Failed. Please try again!
</p>
) : (
<p />
)}
</div>
</div>
</form>
<Footer />
</div>
);
}
}
const mapStateToProps = state => ({
authStatus: state.root.authStatus
});
export default connect(mapStateToProps)(Login);
Action creator-
export const createLogIn = (postLoginData, userName) => (dispatch) => {
console.log('>>> ', userName);
console.log('authenticating');
console.log(btoa(JSON.stringify(jwtdata)));
localStorage.setItem("UserData", btoa(JSON.stringify(jwtdata[userName])))
// dispatch({
// type: SET_AUTH_ERROR,
// payload: false
// })
axios({
method: "POST",
url: "/authenticateUrl",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: postLoginData
})
.then (response => {
dispatch({
type: API_LOG_IN,
payload: response.data
})
localStorage.setItem('AccessToken', response.data.jwt_token);
})
.catch( error => {
console.log("in catch block");
});
}
export const setAuthError = () => {
console.log('inside actions');
return {
type: SET_AUTH_ERROR,
payload: "Authorization Error"
}
}
Reducer-
const initialState = {
authStatus: true
}
const reducerFunc = (state = initialState, action) => {
switch (action.type) {
case API_LOG_IN:
console.log('reducers');
return {...state, logIn: action.payload}
case SET_AUTH_ERROR:
console.log('inside Auth reduccer');
return {...state,authStatus: action.payload}
default: return {...state}
}
}
export default reducerFunc;
I am trying to add a check inside componentWillReceiveProps but that doesn't seem to be working.Instead it always displays me the error message even when the user name is same as the config file.What I want is to display some message like "Authorization failed" if I try to hit the sign in button with wrong User credentials.
!this.props.authStatus ? (
Seems like this line is the problem. Since your authStatus is either "undefined" when no error occurred or "Authentication failed".

Resources