ReactJs - My POST request is always empty - javascript

I'm trying to send a POST request using axios with ReactJS, my POST request will submit when I hit the button, but the data from the textbox is not present. Hoping somebody could point out what I've done wrong. I think I might be going wrong with the state setting.
import React, { Component } from "react";
import axios from "axios";
class SearchBar extends Component {
state = {
search: '',
};
handleChange = event =>{
this.setState({ search: event.target.value});
}
handleSubmit = event => {
event.preventDefault();
const data = {
search: this.state.search
}
axios
.post("http://127.0.0.1:8080/find", {data})
.then(response=>{
console.log(response);
this.setState({ data: response.data });
})
.catch((error) => {
console.log(error);
});
};
render() {
return (
<div className="post">
<form className="post" onSubmit={this.handleSubmit}>
<input
placeholder="Search for music 'Artist - Track'"
type="text" name="name" onChange={this.handleChange}/>
<button type="submit">Search</button>
</form>
<div>
{this.state.data}
</div>
</div>
);
}
}
export default SearchBar;

data is already an object you defined and you wrapped it in another object. So to get your response you will have to do response.data.data
To fix this all you need to do is remove the braces around data in your axios call
axios
.post("http://127.0.0.1:8080/find", data) //removed braces around data
.then(response=>{
console.log(response);
this.setState({ data: response.data });
})
.catch((error) => {
console.log(error);
});

Related

Why is my axios post request not sending data? I'm getting a response that means the fields are empty

I don't know why the data is not sending to the backend.
The API is working perfectly when I tested it on Insomnia. I have even added new users to the database using the API but when I try to add new users from react using redux and axios, it doesn't go instead I get a response saying the fields can't be empty.
I have tried to console.log all the data I'm sending and all the fields are populated properly. I don't know what I'm doing wrong.
I used express-validator for checking inputs as well as normal error handling that's why I get the response that filed is empty.
This is my code
sending the data in redux
export const signin = data => dispatch => {
const config = {
method : "post",
url : "http://localhost:5000/user/signin",
headers : {
"Content-Type":"application/json"
},
body : JSON.stringify(data)
}
console.log(config.body)
axios(config)
.then(res => dispatch({
type : LOGIN_SUCCESS,
payload : res.data
}))
.catch(err => {
dispatch(error_msg(err.response.data, err.response.status))
dispatch({
type : LOGIN_FAIL
})
})
}
React Form component
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import AuthLayout from './AuthLayout'
import Layout from './Layout'
import {connect} from 'react-redux'
import {signin} from '../store/actions/authAction'
import axios from 'axios'
function SignIn({signin}) {
const [value, setValue] = useState({
email : '',
password : ''
})
const handleChange = (e) => {
setValue({
...value,
[e.target.name] : e.target.value
})
}
const handleSubmit = e => {
e.preventDefault()
const {email, password} = value
const oldUser = {
email,
password
}
axios({method : "post",
url : "http://localhost:5000/user/signin",
headers : {
"Content-Type":"application/json; charset=UTF-8",
"Accept":"Token",
"Access-Control-Allow-Orgin":"*",
},
body : JSON.stringify(oldUser)})
.then(res => console.log(res.data))
.catch(err => console.log(err.response.data))
}
return (
<AuthLayout>
<div className="form_container" style={bg}>
<div className="form_title">
<h2>Sign In</h2>
</div>
<form onSubmit={handleSubmit}>
<div className="form_div">
<input type="text" placeholder="Enter Email" name="email" value={value.email} onChange={handleChange} />
</div>
<div className="form_div">
<input type="number" placeholder="Enter Password" name="password" value={value.password} onChange={handleChange} />
</div>
<div className="form_div form_btn">
<button>Submit</button>
</div>
<div className="form_div checkbox">
<input type="checkbox" />
<h4>Remember me</h4>
</div>
</form>
<p>Don't have an account? <Link to="/signup"><span>Sign up</span></Link> </p>
</div>
</AuthLayout>
)
}
const bg = {
backgroundImage: 'url(image/Group1.svg)'
}
const mapStateToProps = state => {
return{
user : state.auth.user
}
}
export default connect(mapStateToProps, {signin})(SignIn)
I didn't include the backend because is working very well.
Thanks to everyone that has helped me to understand the problem, I appreciate all your effort.
I tried some of the solutions presented to me here but it didn't work.
So what I later did was to remove the body variable and replaced it with data in the config object and it started working.
This is the code:
export const signin = data => dispatch => {
const config = {
method : "post",
url : "http://localhost:5000/user/signin",
headers : {
"Content-Type":"application/json",
},
data : JSON.stringify(data)
}
console.log(config.data)
axios(config)
.then(res => dispatch({
type : LOGIN_SUCCESS,
payload : res.data
}))
.catch(err => {
dispatch(error_msg(err.response.data, err.response.status))
dispatch({
type : LOGIN_FAIL
})
})
}
I don't know if is the best solution but in this context, it has worked for me.
This should be changed to fetch,
axios.post('url', 'body', 'headers')
the above is the actual structure of the Axios should be used.
Try the above.
JSON.stringify is not required here
body : JSON.stringify(data),
use
body: data,
because data is stringified in axious by itself, if you feed it already stringified data, you'll have extra escaped json that cannot be considered valid json as backend server

How to make multiple axios.get() requests with componentDidMount() and assign a response value of the 1st to the 2nd?

I am trying to build a web application with Wordpress REST API.
I am making an initial GET request to an endpoint and parsing through the res.data to get some values. But, one of the values featured_media is a parameter for the 2nd GET request I am trying to make. I am finding it difficult to get this value out of that state onto the second GET request.
Here are the states.
state = {
graduatepost: {},
category: '',
featured_media: '',
imgURL: '',
isLoaded: false
}
Here is componentDidMount()
componentDidMount() {
const { featured_media } = this.props;
axios.get(`http://localhost:8000/wp-json/wp/v2/blog/${this.props.match.params.id}`)
.then(res => this.setState({
graduatepost: res.data,
category: res.data.categories[0],
featured_media: res.data.featured_media,
isLoaded: true
}))
.catch(err => console.log(err));
const getImageURL = axios.get(`http://localhost:8000/wp-json/wp/v2/media/${featured_media}`);
Promise.all([getImageURL]).then(res => {
this.setState({
imgURL: res[0].data.media_details.sizes.full.source_url,
isLoaded: true
});
});
}
1st GET request: http://localhost:8000/wp-json/wp/v2/blog/${this.props.match.params.id}
2nd GET request: http://localhost:8000/wp-json/wp/v2/media/${featured_media}
As you can see the 2nd request requires the value featured_media which is in the response of the 1st GET request.
I am rendering the component like this.
render() {
const { graduatepost, category, isLoaded, featured_media, imgURL } = this.state;
if(isLoaded) {
return (
<Styles>
<Fragment>
<Link to='/graduate-posts'>Go Back</Link> // Ignore this
<hr />
<h1>{graduatepost.title.rendered}</h1>
<div dangerouslySetInnerHTML={{__html: graduatepost.content.rendered}}></div>
<h4>Category: {category}</h4>
<h4>featured_media: {featured_media}</h4>
<h4>imgURL: {imgURL}</h4>
</Fragment>
</Styles>
)
}
return <h3>Loading...</h3> // Ignore this
}
When I do the render the component. There is a 404 console error for the 2nd GET request, which states.
GET http://localhost:8000/wp-json/wp/v2/media/undefined 404 (Not Found)
Uncaught (in promise) Error: Request failed with status code 404
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:61)
I am assuming this is because featured_media is empty/undefined but I cannot figure out how to extract that value from the 1st GET request, response.
This may seem like an obvious one but I'm relatively new to working with React.js and APIs together. Your help would be greatly appreciated.
Thank you.
The best way to access the setted data immediately is to use callback.
this.setState accept the callback as its second argument (setState(updater, [callback])), so we should make our second request in our callback statement.
Your code should be something like this:
axios
.get(`http://localhost:8000/wp-json/wp/v2/blog/${this.props.match.params.id}`)
.then((res) =>
this.setState(
{
graduatepost: res.data,
category: res.data.categories[0],
featured_media: res.data.featured_media,
isLoaded: true,
},
() =>
axios
.get(
`http://localhost:8000/wp-json/wp/v2/media/${this.state.featured_media}`
)
.then((res) => {
this.setState({
imgURL: res[0].data.media_details.sizes.full.source_url,
isLoaded: true,
})
})
)
)
.catch((err) => console.log(err))
Have you tried Async function? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
async componentDidMount() {
....
await axios.get ...
....
}
Maybe request it in the response of the 1st axios.get. The reason it isn't working is because this.setState is an async function in React so it's undefined when you access it immediately below.
Try something like:
axios.get(`http://localhost:8000/wp-json/wp/v2/blog/${this.props.match.params.id}`)
.then((res) => {
const state = {
graduatepost: res.data,
category: res.data.categories[0],
featured_media: res.data.featured_media,
isLoaded: true
}
this.setState(state)
return axios.get(`http://localhost:8000/wp-json/wp/v2/media/${state.featured_media}`);
})
.then((res) => {
// do something with res
})
.catch((err) => {
// handle err
});
I have prepared one example where it shows all users and if you click to see posts button, it will show all the posts for that user.
App.js
class App extends React.Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/posts">Posts</Link>
</li>
</ul>
<hr/>
<Switch>
<Route exact path="/">
<UserList/>
</Route>
<Route path="/posts">
<PostListPageByUser/>
</Route>
</Switch>
</div>
</Router>
);
}
}
export default App;
UserList Component
import React from 'react';
import axios from 'axios';
import PostListPageByUser from "./PostListPageByUser";
import {withRouter} from "react-router-dom";
class UserList extends React.Component {
state = {
users: [],
showPostList: false,
user: {}
};
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const users = res.data;
console.log(users);
this.setState({users});
})
}
handleClick = (user) => {
console.log(user);
this.setState({showPostList: true, user: user});
this.props.history.push({
pathname: '/posts',
user: user
});
};
render() {
return (
<div>
<ul>
{this.state.users ? this.state.users.map(user => <div key={user.id}>
<span style={{minWidth: 400}}>{user.name} </span>
<button onClick={() => {
this.handleClick(user)
}}>See Posts
</button>
</div>) : null}
</ul>
{this.state.showPostList ? <PostListPageByUser user={this.state.user}/> : null}
</div>
)
}
}
export default withRouter(UserList);
PostListByUser Component
import React from "react";
import axios from 'axios';
import {withRouter} from "react-router-dom";
class PostListPageByUser extends React.Component {
signal = axios.CancelToken.source();
state = {
posts: [],
};
componentDidMount() {
if(!this.props.location.user){
alert('Please click see posts button');
this.props.history.push('/');
return;
}
axios.get(`https://jsonplaceholder.typicode.com/posts?userId=${this.props.location.user.id}`, {
cancelToken: this.signal.token,
})
.then(res => {
this.setState({posts: res.data});
console.log(res.data, 'Posts');
}).catch(err => {
console.log(err);
});
}
render() {
return (
<div>
<ul>
{
this.state.posts ? this.state.posts.map(post => <li key={post.id}>{post.title}</li>) : null
}
</ul>
</div>
)
}
}
export default withRouter(PostListPageByUser);

Save and Edit post in reactjs and redux

I've been trying to create a blog like website where user can add new post, save them and edit them later. I'm making this website in reactjs and redux. I've few confusions as to how to edit the post, like how will my website know that the user has clicked on this certain post to edit. To do I've used link from react router with the id at the end of the url but I'm not sure if it's the right way to do. Also, when I open the editor page of an existing post, it should load as it was last saved, i.e both the title input and the textarea should already be loaded with text when a user clicks on an already existing posts from the homepage.
I've created a codesandbox of the website. I'm not sure why all the lines in the switch statements in the reducer file is underlined with red.
this is my home.js file where the snippets will load
import React from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import { onLoad, setEdit } from "./actions/posts";
import { connect } from "react-redux";
class Home extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
//Load all the snippets
onLoad();
}
render() {
const { snippets } = this.props;
return (
<div className="container">
<div className="row pt-5">
<div className="col-12 col-lg-6 offset-lg-3">
<h1 className="text-center">Snippets</h1>
</div>
</div>
<div className="row pt-5">
<div className="col-12 col-lg-6 offset-lg-3">
{snippets.map(snippet => {
return (
<div className="card my-3" key={snippet.snippetData.snippetId}>
<div className="card-header">{snippet.title}</div>
<div className="card-body">{snippet.snippetDescription}</div>
<div className="card-footer">
<div className="row">
<button
// onClick={() => this.handleEdit(snippet)}
className="btn btn-primary mx-3"
>
<Link to={`/editor/:${snippet.snippetData.snippetId}`}>
Edit
</Link>
</button>
</div>
</div>
</div>
);
})}
</div>
</div>
</div>
);
}
}
const mapStateToProps = state => ({
snippets: state.snippets,
snippetData: state.snippetData
});
export default connect(
mapStateToProps,
{ onLoad, setEdit }
)(Home);
editor.js page
import React, { Component } from "react";
import { connect } from "react-redux";
import { savePost, retrievePost } from "./actions/posts";
class Editor extends Component {
state = {
title: "",
enteredText: ""
};
componentDidMount() {
//Load the snippet
retrievePost(); // will it load the snippetId too?
}
handleChange = event => {
const { value } = event.target;
this.setState({
enteredText: value
});
};
// Save Snippet
performSave = snippetData => {
const { enteredText, title } = this.state;
savePost(snippetData.snippetId, enteredText, title); //is it the right way to send the parameters to save the post??
};
render() {
return (
<>
<input
type="text"
id="titletext"
placeholder="Enter title here"
limit-to="64"
className="inptxt"
onChange={title => this.setState({ title })}
/>
<button
className="btn savebtn"
onClick={() => this.handlePost({ ...this.state })}
>
Save Snippet
<i className="fas fa-save" />
</button>
<div
contentEditable={true}
spellCheck="false"
name="enteredText"
placeholder="Enter your text here"
onChange={this.handleChange}
/>
</>
);
}
}
const mapStateToProps = state => ({
snippetData: state.snippetData
});
export default connect(
mapStateToProps,
{ savePost, retrievePost }
)(Editor);
actions.js file
import { SAVE_POST, UPDATE_POST, RETRIEVE_POST, HOME_LOADED } from "./types";
export const savePost = ({
snippetId,
snippetDescription,
snippetTitle
}) => async dispatch => {
const config = {
headers: {
"Content-Type": "application/json"
}
};
let snippetData = { snippetId, snippetDescription, snippetTitle };
try {
if (snippetId == null) {
const res = await axios.post(
"/api/save",
JSON.stringify(snippetData),
config
);
snippetData.snippetId = res.data;
dispatch({
type: SAVE_POST,
payload: snippetData
});
} else {
const res = await axios.post(
"/api/update",
JSON.stringify(snippetData),
config
);
dispatch({
type: UPDATE_POST,
payload: snippetData
});
}
} catch (err) {
console.log(err);
}
};
// Retrieve post
export const retrievePost = snippetId => async dispatch => {
try {
const res = await axios.post(`/api/snippetdata/${id}`);
dispatch({
type: RETRIEVE_POST,
payload: res.data
});
} catch (err) {
console.error(err);
}
};
//Retrieve all the post
export const onLoad = () => async dispatch => {
try {
const res = await axios.post(`/api/mysnippets/`);
dispatch({
type: HOME_LOADED,
payload: res.data
});
} catch (err) {
console.error(err);
}
};
// edit a post
First, I have fixed some problems for you:
https://codesandbox.io/s/amazing-bird-dd2mb
I did not fix the editor page, cuz I give up, it is meaningless to give you a working code while learning nothing.
I suggest you stop playing react now, you do not have enough experience to use a complex framework.
What problem your code has:
Wrongly import a commonJS module
Misuse combineReducers
Misuse html form element
Misuse js switch
Do not understand redux state correctly
Do not understand reducer fully
Do not have basic debuging skills
...
STOP WRITING CODE THAT YOU DO NOT UNDERSTAND
This project is too complex for a beginner.
I suggest you:
Implement a counter in vanilla js
Implement a todo list in vanilla js
RE-implement the counter with pure react, no redux, no react-router
RE-implement the counter with react + redux
RE-implement the counter with react + redux + thunk
RE-implement the counter with react + redux + saga
Repeat 3-6 but a todo list.
Then try to code a blog.

How to use form input data as input for axios request in react native?

I need suggestion and help on how to use text from input form as the input for axios request in react native.
Right now I am adding a SignIn screen to my app. To retrieve any API for my app, there is a need for token. Before, I just made a one action file using redux to fetch token and store it inside a reducer.
For this case, I am trying to use email and password from form input while signing in as the data for me to retrieve the token. Long story short, this is my code SignInScreen.js right now
import React, { Component, AsyncStorage } from 'react';
import { View, Text } from 'react-native';
import { FormLabel, FormInput, Button, Card } from 'react-native-elements';
import axios from 'axios';
import { FETCH_TOKEN } from '../actions/types';
import apiConfig from '../services/api/url_config';
class SignInScreen extends Component {
constructor(props) {
super(props);
this.state = {
loggedIn: null,
email: '',
password: '',
error: '',
loading: false
};
}
onButtonPress = () => async (dispatch) => {
let email = this.state.email;
let password = this.state.password;
AsyncStorage.getItem('auth', (res) => {
let TOKEN_URL = apiConfig.url + 'tokens';
let auth = {};
if (res === null) {
auth = {};
} else {
auth.push({
email: email,
password: password,
role: 'user'
});
console.log(auth);
axios.post(TOKEN_URL, auth)
.then((response) => {
console.log(response.data.token);
dispatch({ type: FETCH_TOKEN, payload: response.data.token });
this.props.navigation.navigate('Home');
})
.catch((e) => {
console.log(e);
this.props.navigation.navigate('SignIn');
});
}
});
}
render() {
return (
<View>
<Card>
<FormLabel>Email</FormLabel>
<FormInput
placeholder="user#email.com"
value={this.state.email}
onChangeText={email => this.setState({ email })}
/>
</Card>
<Card>
<FormLabel>Password</FormLabel>
<FormInput
secureTextEntry
placeholder="password"
value={this.state.password}
onChangeText={password => this.setState({ password })}
/>
</Card>
<Card>
<Button
title="Log In"
onPress={this.onButtonPress}
/>
</Card>
</View>
);
}
My actions/types
export const FETCH_TOKEN = 'fetch_token';
My tokenReducer.js
import {
FETCH_TOKEN
} from '../actions/types';
export default function tokenReducer(state = '', action) {
switch (action.type) {
case FETCH_TOKEN:
return action.payload;
default:
return state;
}
}
I run this code and when I click on LogIn button, there is no result at all. Even the console log too also did not appear. I do not know how should I troubleshoot this problem if there is no console log I can refer to.
As you can see, to get the token, email and password, as well as the hardcoded value for 'role', need to be pass alongside the axios.post request. I am expecting if the request is successful, it will navigate the user to the Home screen while if it not, it will navigate the user to the SignIn screen again.
My question is, if I want to use the data or text from form input to be pass alongside axios request, am I on the right track with this code? If it not, please help me by sharing your suggestion.
Thank you.
Using fetch to replace your axios request :
fetch(TOKEN_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(auth),
})
.then(response => response.json())
.then(responseData => /* responseData.token to access your token */ )
.catch(err => /* Handle Error */ )
});
Maybe connect your component with redux to use this.props.dispatch to dispatch actions instead of asyn func :
import connect function from redux :
import { connect } from 'react-redux'
Add at the end of your file :
export default connect()(SignInScreen)
Remove async func :
onButtonPress = () => {
use this.props.dispatch to dispatch actions :
this.props.dispatch({ type: FETCH_TOKEN, payload: response.data.token });
You can also get state from redux store in your component props by using mapStateToProps
function mapStateToProps(state) {
return { isLoggedIn: state.isLoggedIn } // accessed by this.props.isLoggedIn in your component
}
export default connect(mapStateToProps)(SignInScreen)

React.js - Loading single post data from API correctly

I am fairly new to React, and trying to work my way through how I should properly be loading data from my API for a single post.
I have read that I should be using "componentDidMount" to make my GET request to the API, but the request is not finished by the time the component renders. So my code below does not work, as I am recieving the error: "Cannot read property setState of undefined".
What I am doing wrong here? Should I be calling setState from somewhere else? My simple component is below - thanks.
import React from 'react';
import Header from './Header';
import axios from 'axios';
class SingleListing extends React.Component {
constructor(props) {
super(props);
this.state = {
listingData: {}
}
}
componentDidMount() {
// Get ID from URL
var URLsegments = this.props.location.pathname.slice(1).split('/');
// Load the listing data
axios.get('/api/listing/' + URLsegments[1])
.then(function(res){
let listingDataObject = res.data;
console.log(listingDataObject);
this.setState({
listingData: listingDataObject
});
})
.catch(function(err){
console.log(err);
});
}
render() {
console.log('helsdfdsfsdflssosso');
console.log(this.state.listingData);
return (
<div className="SingleListing">
<Header />
<div className="container">
<div>Property Address: {this.state.listingData.propertyAddress}</div>
This is a single listing
</div>
</div>
)
}
}
export default SingleListing;
You just need to change what you render depending on whether the data is loaded or not yet.
Also, you should use arrow functions when handling the axios response, otherwise this is not set correctly.
class SingleListing extends React.Component {
constructor(props) {
super(props);
this.state = {
listingData: null,
};
}
componentDidMount() {
// Get ID from URL
const URLsegments = this.props.location.pathname.slice(1).split('/');
// Load the listing data
axios
.get(`/api/listing/${URLsegments[1]}`)
.then(res => {
const listingDataObject = res.data;
console.log(listingDataObject);
this.setState({
listingData: listingDataObject,
});
})
.catch(err => {
console.log(err);
});
}
render() {
const isDataLoaded = this.state.listingData;
if (!isDataLoaded) {
return <div>Loading...</div>;
}
return (
<div className="SingleListing">
<Header />
<div className="container">
<div>Property Address: {this.state.listingData.propertyAddress}</div>
This is a single listing
</div>
</div>
);
}
}
export default SingleListing;
this is out of scope you need to include it. here is a solution using es2015 arrow functions =>
axios.get('/api/listing/' + URLsegments[1])
.then((res) => {
let listingDataObject = res.data;
console.log(listingDataObject);
this.setState({
listingData: listingDataObject
});
})
.catch((err) => {
console.log(err);
});

Categories

Resources