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;
Related
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
}
I am rather new to React and am making an app with the MERN stack to create, read, update and delete recipes but I'm getting the warning from React that I don't have a unique key for my recipe items. However, when I refresh my browser the warning goes away and my recipe object now has the id. It looks like the recipe ID is not being posted until after the recipe items are re-rendered. I don't get the warning if I pass the index as the key but I am just really wanting to understand why I keep getting this error when trying to use the ID generated from MongoDB.
class RecipeContiner extends Component {
constructor(props) {
super(props);
this.state = {
title: "",
ingredients: "",
summary: "",
recipes: []
}
}
//GET RECIPES
componentDidMount() {
const url = 'http://localhost:5000/recipes/';
axios.get(url)
.then((res) => {
this.setState({ recipes: res.data })
}).catch(err => {
console.log(err);
});
}
onChangeHandler = (e) => {
this.setState({ [e.target.name]:e.target.value})
}
//POST RECIPE
onSubmitHandler = (e) => {
e.preventDefault();
const recipe = {
title: this.state.title,
ingredients: this.state.ingredients,
summary: this.state.summary
}
const url = 'http://localhost:5000/recipes/add';
axios.post(url, recipe)
.then(res => console.log('new recipe!', res.data));
this.setState({
recipes: [...this.state.recipes, recipe],
});
e.target.reset();
}
render() {
return (
<div>
<form onSubmit={this.onSubmitHandler}>
<label>Title:</label>
<input type="text" onChange={this.onChangeHandler} name="title"/>
<label>Ingredients:</label>
<input type="text" onChange={this.onChangeHandler} name="ingredients"/>
<label>Summary:</label>
<input type="text" onChange={this.onChangeHandler} name="summary"/>
<input type="submit" value="Submit" />
</form>
<RecipeList recipes={this.state.recipes} />
<Fab color="primary" aria-label="add">
<AddIcon />
</Fab>
</div>
);
}
//RECIPE LIST COMPONENT
const RecipeList = (props) => {
console.log('props.recipes', props.recipes)
const recipes = props.recipes;
return (
<div>
<ul>
{recipes.map((recipe, index) => (
<RecipeItem
key={recipe._id}
title={recipe.title}
ingredients={recipe.ingredients}
summary={recipe.summary}
/>
))}
</ul>
</div>
);
}
//RECIPE ITEM COMPONENT
const RecipeItem = (props) => {
return (
<li>
<div>{props.title}</div>
<div>{props.ingredients}</div>
<div>{props.summary}</div>
</li>
)
}
}```
[1]: https://i.stack.imgur.com/aZtEO.png
your state don't get the id after you post id. you just add the new recipe from the client and not form the server with the id.
axios.post(url, recipe)
.then(res => this.setState({
recipes: [...this.state.recipes, res.data],
} ,()=>console.log('new recipe!', res.data)));
will do the trick.
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?
I am newbie in react and I have some trouble that I'd like to solve.
I would like to know how can I show and hide react components before and after to do a rest call.
I have the follow component:
class Loading {
render(){
return (
<div >
<Modal isOpen={true} centered >
<ModalHeader>Loading...</ModalHeader>
<ModalBody >
<div align='center' className="mt-2 mb-2">
<Spinner style={{ width: '4rem', height: '4rem' }} color="primary" />
</div>
</ModalBody>
</Modal>
</div>
)
}
}export default Loading;
And I would like to show this component in other module before to call a rest api and hide this component after the data come. The ideia is some like this:
class List extends Component {
constructor(props) {
super(props)
this.state = {
show : false
}
}
// HERE I WOULD LIKE TO SHOW THE LOADING COMPONENT
callRestApi = () => {
axiosAuth.get(url, getConfig())
.then(response => {
console.log(response.data)
this.setState({
eventos: response.data
})
}).catch(error => {
console.log(error);
return null
});
// HERE I WOULD LIKE TO HIDE THE LOADING COMPONENT
}
render() {
return(
<div>
<Button className="mr-2" color="primary" size="sm" onClick={this.callRestApi}>List All</Button>
</div>
How can I do it?
You can create state that dictates whether the loading spinner is visible or not. And append one last .then in the promise chain to modify it.
class List extends Component {
constructor(props) {
super(props)
this.state = {
show : false,
loaderVisible: true
}
}
// HERE I WOULD LIKE TO SHOW THE LOADING COMPONENT
callRestApi = () => {
axiosAuth.get(url, getConfig())
.then(response => {
console.log(response.data)
this.setState({
eventos: response.data
})
}).catch(error => {
console.log(error);
return null
}).then(() => {
this.setState({loaderVisible: false });
});
}
render() {
return(
<div>
{
this.state.loaderVisible? <Loading /> : ''
}
<Button className="mr-2" color="primary" size="sm" onClick={this.callRestApi}>List All</Button>
</div>
Then utilize ternary syntax on the spinner to determine visibility.
We use state to implement this. Here is the pseudo code.
class List extends Component {
state = { loading: false }
callRestApi = async () => {
this.setState({ loading: true });
await fetch(...);
this.setState({ loading: false });
}
render() {
<div>
{this.state.loading && <Loading />}
<button onClick={this.callRestApi}>List All</button>
</div>
}
}
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.