How make post request without issues with setState in react? - reactjs

I have value that i want to update and send an update post request , so i tried this:
EDIT
i add more code that represenet the all component:
import React from 'react'
import axios from 'axios'
import {Card} from 'react-bootstrap'
class SubmitPage extends React.Component{
constructor(props) {
super(props)
this.state={formname:'',
fields:[''],
values:[''],
submissions:0
}
}
handleChange=this.handleChange.bind(this)
saveChanges=this.saveChanges.bind(this)
componentDidMount=this.componentDidMount.bind(this)
//get the Object from DB and initialize new state
componentDidMount()
{
axios.get('http://localhost:2000/form/'+this.props.match.params.id).then(response =>{
this.setState({
formname:response.data.formname,
fields:response.data.fields,
submissions:response.data.submissions
})
})
.catch(function(error){
})
}
handleChange(e,index)
{
this.setState({
values: {
...this.state.values,
[index.index]: e.target.value
}
});
}
async saveChanges(e)
{
e.preventDefault();
//update the values in field array
const {values}=this.state;
const fields=this.state.fields;
Object.keys(values).map(key =>
fields[key].push(values[key])
)
//get submission and update it
axios.get('http://localhost:2000/form/'+this.props.match.params.id)
.then(response =>{
this.setState({
submissions: response.data.submissions
})
console.log(this.state.submissions)
})
.catch(function(error){
console.log(error);
})
//let submissionsUpdate=this.state.submissions;
// submissionsUpdate=submissionsUpdate+1;
this.setState({
submissions: this.state.submissions+1}, ()=> {
const form={
formname:this.state.formname,
fields:this.state.fields,
submissions: this.state.submissions
}
axios.post('http://localhost:2000/form/update/'+this.props.match.params.id,form) //post after sumbmission value update
.then(res => console.log(res.data));
});
window.location='/'
}
render(){
const {fields}=this.state
return(
<div style={{width:'35%' , margin:"0 auto" ,marginTop:"3%"}}>
<Card >
<Card.Header as="h5">{this.state.formname}</Card.Header>
<Card.Body>
<Card.Text>
<div>{fields.length!==0&&fields.map((fields,index)=> {
return (
<div key={fields[0]}>
<div style={{fontSize:'15px' , marginBottom:"-1px"}}>{fields[0]}</div>
<div><input onChange={(e) => this.handleChange(e, {index})} type={fields[1]}></input></div>
</div>
)
})
}
</div>
<button style={{width:100, marginTop:"10px", marginBottom:"20px"}} type="submit" onClick={this.saveChanges} className="btn btn-dark"> Submit</button>
</Card.Text>
</Card.Body>
</Card>
</div>)
}
}
export default SubmitPage
my goal is to increase counter by 1 , but because the setState is asych, something goes wrong , and the result is or increasing by strange number or no change.
what i am doing wrong?

Related

How can i make it so that data sends only one item in array to cart

I'm trying to add the particular item in cart (which is located at react-db.json file) on button click, and later display it on a different page. Also if anyone has a simpler way of doing this it would be really helpfull
import React, { Component } from "react";
import Product from "./Product.jsx";
import { Kosarica } from "./kosarica.jsx";
import axios from "axios";
export default class Cart extends Component {
constructor(props) {
super(props);
this.state = {
products: []
};
}
render() {
return (
<div>
<div className="row">
{this.state.products.map(prod => {
return (
<Product
key={prod.id}
product={prod}
onIncrement={this.handleIncrement}
onDecrement={this.handleDecrement}
onDelete={this.handleDelete}
>
<button
id="btn"
className="btn btn-primary"
onClick={this.handleClick}
>
Dodaj
</button>
</Product>
);
})}
</div>
</div>
);
}
componentDidMount = async () => {
var response = await fetch("http://localhost:5000/products", {
method: "GET"
});
var prods = await response.json();
this.setState({ products: prods });
};
};
handleClick = product => {
let data = [this.state.products];
fetch("http://localhost:5000/cart", {
method: "POST",
mode: "cors",
body: JSON.stringify(data)
});
console.log("data sent", data);
};
}
note - increment, decrement and delete are working fine that's why i didn't post them here
<button
id="btn"
className="btn btn-primary"
onClick={() => this.handleClick(prod)}
>
Then add cartItems into state, and in click handler :
handleClick = (prod) => {
this.setState({
cartItems: [
...this.state.cartItems,
prod
],
});
.... // then use cartItems to pass it to api end-point
}

React Loader - Trying to get a loader when api request is made and to stop it when response is fetched

What I want is that, when I click on search button, then a loader/spinner should appear on screen until the data is fetched, when the data is fetched it should disappear.
Container.jsx
import React from 'react';
import './container.css'
import Weather from './weather';
var Loader = require('react-loader');
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
location: "",
weather: [],
loaded:false
};
}
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
componentDidMount() {
this.setState.loaded=false;
}
continue = (e) => {
this.setState({loaded:true});
const { location } = this.state;
const rawurl = 'http://api.weatherstack.com/current?access_key=d8fefab56305f5a343b0eab4f837fec1&query=' + location;
const url = rawurl;
e.preventDefault();
if (location.length < 1) {
return alert('Enter the details');
}
else {
fetch(url)
.then(response => response.json())
.then(data =>{
this.setState({weather:[data],loaded:false});
})
.catch(err => console.log("error ",err))
}
};
render() {
console.log(this.state.weather);
const weather =
this.state.weather.length> 0 ?
this.state.weather.map(item => (<Weather location={item.location.name} temperature={item.current.temperature} weather={item.current.weather_descriptions[0]} windSpeed={item.current.wind_speed} windDegree={item.current.wind_degree} windDir={item.current.wind_dir} humidity={item.current.humidity} visibility={item.current.visibility} />
))
:<span></span>
return (
<div id="container">
<div class="searchicon">
<input type="search" placeholder="Enter City !!" type="text" name="location" value={this.state.location} onChange={this.handleChange}></input>
<label class="icon">
<button onClick={this.continue} id="btn"><span class="fa fa-search"></span></button>
</label>
</div>
<div>
<Loader loaded={this.state.loaded}>
{weather}
</Loader>
</div>
</div>
);
}
}
export default Container;
What I am using here is react-loader
But right now,its not happening in the way I want, sometime before clicking the serach button it appears and when data is fetched it stops, i want to start it when the api req is made after click on search button and to stop when data is fetched.
first of all you should in the setState after fetching the data to make
this.setState({weather:[data],loaded:true});
second there's another way to do it you can separate the code in the return function like
{ !this.state.loaded ? <Loader loaded={false} options={options} className="spinner" />:{weather}}
as per the Doc in npm you can check it react-loader

Calling Fetch in React App.js with Prop Drilling

So I would like to call fetch from a function (submitURL) in App.js. If I create "componentDidMount()" in App.js and call fetch there, it works, but not from submitURL. I believe this is because submitURL is called via prop drilling. How would I call fetch from submitURL?
App.js
class App extends Component {
state = {
channelURL: '',
videos: []
}
submitURL = (value) => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => console.log(json))
this.setState({
channelURL: value
});
}
render() {
console.log(this.state)
return (
<div className="App">
<h1> Title </h1>
<Channel submitURL={this.submitURL} url={this.state.channelURL}/>
<Videos videos={this.state.videos}/>
</div>
);
}
}
export default App;
Channel.js
class Channel extends Component {
state = {
value: this.props.url
}
handleChange = (e) => {
this.setState({
value: e.target.value
});
}
render() {
return (
<div>
<h1> Enter Channel URL </h1>
<form onSubmit={this.props.submitURL.bind(this, this.state.value)}>
URL: <input type="text" name="url" value={this.state.value} onChange={this.handleChange}/>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
export default Channel;
submitURL = (value) => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => this.setState({
channelURL: json
}))
}

React axios DELETE and POST adding to database but not updating state

When I delete an item, it is deleted from the database, but state is not updated until I refresh the page.
My understanding is that I don't want to update state directly, I want to make a copy of state, modify it, then overwrite the existing state, which should trigger a new render as it also removes the item from the database.
So I would think a spread operator would be ideal for this, but I can't seem to get it to re-render.
class Projects extends Component {
state = {
projects: []
};
getProjects() {
axios
.get('http://localhost:5309/api/projects')
.then(response => {
this.setState({ projects: response.data });
})
.catch(error => console.log(error));
}
deleteProject(event) {
axios
.delete(`http://localhost:5309/api/projects/${event.target.value}`)
.then(response => {
this.setState({ projects: response.data });
})
.catch(error => {
console.log(error);
});
}
componentDidMount() {
this.getProjects();
}
render() {
return (
<div className="Projects">
<h1>Projects</h1>
<div className="projectContainer">
{this.state.projects.map(project => {
return (
<div className="projects" key={project.id}>
<Card>
<CardBody>
<CardTitle>Name: {project.name}</CardTitle>
<CardText>
Project Description: {project.description}
</CardText>
</CardBody>
<Button color="secondary">Edit</Button>
<Button
color="danger"
type="submit"
value={project.id}
onClick={this.deleteProject}
>
Delete
</Button>
</Card>
</div>
);
})}
</div>
</div>
);
}
}
export default Projects;

Search functionality and fetch api in React

I'm working on an app that makes a call to Unsplash's API and displays the response. I was able to get/display the response easily with just the /photos endpoint when I had the fetch request in the componentDidMount(), but I want to make the app searchable, so I added performSearch() with a default query.
But adding performSearch caused this error:
TypeError: cannot read property 'map' of undefined
This is the JSON I'm getting back when I test:
Search endpoint + query
I've tried other solutions I've found on the forums, but so far nothing's fixed the problem. I'm definitely getting back an array, so shouldn't map work?
class App extends Component {
constructor() {
super();
this.state = {
results: [],
loading: true
};
}
componentDidMount() {
this.performSearch();
}
performSearch = (query = 'camping') => {
fetch(`https://api.unsplash.com/search/photos?page=3&query=${query}&client_id=${client_id}`)
.then(response => response.json())
.then(responseData => {
this.setState({
results: responseData.data,
loading: false
});
})
.catch(error => {
console.log('Error fetching and parsing data', error);
});
}
render() {
return (
<div className = "App">
<SearchPhotos onSearch = {this.performSearch} />
<div>
{
(this.state.loading) ? <p>Loading</p> :<PhotoList results={this.state.results} />
}
</div>
</div>
);
}
}
export default 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>
import React from 'react';
const PhotoList = props =>
<ul>
{props.results.map((result, index) =>
<li key={index}>
<img src={result.urls.small} key={result.id} />
</li>
)}
</ul>;
export default PhotoList;
import React, { Component } from 'react';
class SearchPhotos extends Component {
state = {
searchText: ''
}
onSearchChange = e => {
this.setState({
searchText: e.target.value
});
}
handleSubmit = e => {
e.preventDefault();
this.props.onSearch(this.query.value);
e.currentTarget.reset();
}
render() {
return(
<form className="search-form" onSubmit={this.handleSubmit}>
<input type="search"
onChange={this.onSearchChange}
name="search"
ref={(input) => this.query = input}
placeholder="Search..." />
<button className="search-button" type="submit" id="submit">Go!</button>
</form>
);
}
}
export default SearchPhotos;
performSearch = (query = 'camping') => {
fetch(`https://api.unsplash.com/search/photos?page=3&query=${query}&client_id=${client_id}`)
.then(response => response.json())
.then(responseData => {
this.setState({
results: responseData.results,
loading: false
});
})
.catch(error => {
console.log('Error fetching and parsing data', error);
});
}
responseData.results is the array that your are looking for.

Resources