React - Axios Showing Message to User - javascript

want to show message to user. console log working fine im not sure why i cant show to user.
tried several methods to fix.
error message from axios = 'Request failed with status code 404'
import { useParams, Link, Route, Routes } from 'react-router-dom';
import { useState, useEffect } from 'react';
import axios from 'axios';
function User() {
const { id } = useParams();
const [user, setUser] = useState(null);
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(true);
console.log("error", error);
useEffect(() => {
axios("https://jsonplaceholder.typicode.com/users/" + id)
.then(res => setUser(res.data))
.catch(error => {
console.log("Error=>", error);
console.log(error.message);
setError(typeof (error.message));
console.log("Check",error.message == 'Request failed with status code 404');
})
.finally(() => {
setIsLoading(false);
});
}, [id]);
return (
<div>
{error.message == 'Request failed with status code 404' ? <p>{error.message}</p> :
isLoading ? <h2>Loading...</h2> :
<div>
<h3>User Info</h3>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
</div>
}
<Link to={`/users/${parseInt(id) + 1}`}><button>Next User</button></Link>
</div>
)
}
export default User

You have a couple bugs:
use === when comparing instead of == to avoid type coercion
when setting state setError(typeof (error.message));, remove typeof of it , setError(error.message);
when testing the error.message simply test error and also display error
Note: I removed <Link> only for demo to stop throwing errors on Routes
import { useParams } from "react-router-dom";
import { useState, useEffect } from "react";
import axios from "axios";
function User() {
const { id } = useParams();
const [user, setUser] = useState(null);
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
axios("https://jsonplaceholder.typicode.com/users/" + id)
.then((res) => setUser(res.data))
.catch((error) => setError(error.message))
.finally(() => setIsLoading(false));
}, [id]);
return (
<div>
{error === "Request failed with status code 404" ? (
<p>{error}</p>
) : isLoading ? (
<h2>Loading...</h2>
) : (
<div>
<h3>User Info</h3>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
</div>
)}
</div>
);
}
export default User;

Try to re-organize your logical rendering check the conditions
import { useParams, Link, Route, Routes } from 'react-router-dom';
import { useState, useEffect } from 'react';
import axios from 'axios';
function User() {
const { id } = useParams();
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(true);
console.log("error", error);
useEffect(() => {
axios("https://jsonplaceholder.typicode.com/users/" + id)
.then(res => setUser(res.data))
.catch(error => {
console.log("Error=>", error);
console.log(error.message);
// set error instead of type of the error
setError(error);
console.log("Check",error.message == 'Request failed with status code 404');
})
.finally(() => {
setIsLoading(false);
});
}, [id]);
return (
<div>{loading?
<h2>Loading...</h2>
:
<div>
{error?.message ===null?
<p>'Request failed with status code 404'<p> : <p>{error.message}</p>}
<h3>User Info</h3>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
</div>
</div>
}
<Link to={`/users/${parseInt(id) + 1}`}><button>Next User</button></Link>
</div>
)
}
export default User

Seeing as you are using empty string in the state, just pass the error.message directly, and then your error will contain a string.
function User() {
const { id } = useParams();
const [user, setUser] = useState(null);
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(true);
console.log("error", error);
useEffect(() => {
axios("https://jsonplaceholder.typicode.com/users/" + id)
.then(res => setUser(res.data))
.catch(error => {
console.log("Error=>", error);
console.log(error.message);
setError(error.message); // change this
console.log("Check",error.message == 'Request failed with status code 404');
})
.finally(() => {
setIsLoading(false);
});
}, [id]);
return (
<div>
{/* and change this as well */}
{error ? <p>{error.message}</p> :
isLoading ? <h2>Loading...</h2> :
<div>
<h3>User Info</h3>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
</div>
}
<Link to={`/users/${parseInt(id) + 1}`}><button>Next User</button></Link>
</div>
)
}

Related

Why can't clear error message after show - axios - react

First question for context
I'm showing using with localhost:3000/users/:id
API has 10 user so if request to localhost:3000/users/11 should show error message
Also want to show message for connection problems too
I've tried to add setError(""); inside finally block but error message stopped working.
If I don't add this time working when I get error but when I fix error error still appear.
I want to show user details again
import { useParams } from "react-router-dom";
import { useState, useEffect } from "react";
import axios from "axios";
function User() {
const { id } = useParams();
const [user, setUser] = useState(null);
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
axios("https://jsonplaceholder.typicode.com/users/" + id)
.then((res) => setUser(res.data))
.catch((error) => setError(error.message))
.finally(() => setIsLoading(false));
}, [id]);
return (
<div>
{error === "Request failed with status code 404" ? (
<p>{error}</p>
) : isLoading ? (
<h2>Loading...</h2>
) : (
<div>
<h3>User Info</h3>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
</div>
)}
</div>
);
}
export default User;
You have to clear your error when the response is OK
.then((res) => {
setUser(res.data);
setError("")
})
import { useParams } from "react-router-dom";
import { useState, useEffect } from "react";
import axios from "axios";
function User() {
const { id } = useParams();
const [user, setUser] = useState(null);
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
axios("https://jsonplaceholder.typicode.com/users/" + id)
.then((res) => {
setUser(res.data);
setError("")
})
.catch((error) => setError(error.message))
.finally(() => setIsLoading(false));
}, [id]);
return (
<div>
{error === "Request failed with status code 404" ? (
<p>{error}</p>
) : isLoading ? (
<h2>Loading...</h2>
) : (
<div>
<h3>User Info</h3>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<p>Phone: {user.phone}</p>
</div>
)}
</div>
);
}
export default User;

React Fetch not working for one link but works for another

I am trying to use react to fetch api information (see below) but it is not returning any values but works when I use a different link. Not sure what the issue is with the second link. How do I make the second link work or is there a different method?
import React, { useState, useEffect } from "react";
import axios from "axios";
export default function App() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
getData()
}, []);
async function getData() {
// await axios("https://randomuser.me/api") // <----- this works
await axios("https://api.sampleapis.com/wines/reds") // <----- this does not work
.then((response) => {
setData(response.data);
console.error("No Error fetching data: fds");
})
.catch((error) => {
console.error("Error fetching data: ", error);
setError(error);
})
.finally(() => {
setLoading(false);
});
}
if (loading) return "Loading...";
if (error) return "Error!"; //dfdsaf
return ( <>
{/* <img src={data.results[0].picture.medium} alt="random user" /> */}
<pre>{JSON.stringify(data, null, 2)}</pre>
</>
); }
The structures of the returning data from each APIs are different from each other.
https://randomuser.me/api -> returns {"results":[{"gender"...
https://api.sampleapis.com/wines/reds -> returns [{"winery":"Maselva","wine"...
So obviously just changing the URL won't work. You have to change the code accordingly to the structure of the returned data to access them properly.
The response structure is different and you may not need to use .then and .catch as you have already used Async/Await.
Here's a working example in codesandbox
<script type="text/babel">
// import React, { useState, useEffect } from "react";
// import axios from "axios";
const { useState, useEffect } = React;
function App() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [randomUserData, setRandomUserData] = useState(null);
const [randomUserLoading, setRandomUserLoading] = useState(true);
const [randomUserError, setRandomUserError] = useState(null);
useEffect(() => {
getRandomUserData();
getSampleApiData();
}, []);
async function getSampleApiData() {
try {
const response = await axios("https://api.sampleapis.com/wines/reds");
setData(response.data);
console.error("No Error fetching data: fds");
} catch (error) {
console.error("Error fetching data: ", error);
setError(error);
}
setLoading(false);
}
async function getRandomUserData() {
try {
const response = await axios("https://randomuser.me/api");
setRandomUserData(response.data);
console.error("No Error fetching data: fds");
} catch (error) {
console.error("Error fetching data: ", error);
setRandomUserError(error);
}
setRandomUserLoading(false);
}
if (loading || randomUserLoading) return "Loading...";
if (error || randomUserError) return "Error!";
return (
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(2, 1fr)",
width: "100%"
}}
>
<div>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
<div>
<pre>{JSON.stringify(randomUserData, null, 2)}</pre>
</div>
</div>
);
}
// export default App;
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
<div id="app"></div>
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/axios#0/dist/axios.js"></script>
<script crossorigin src="https://unpkg.com/#babel/standalone#7/babel.js"></script>

How to show search result not found message

import React, { useState, useEffect } from 'react'
import axios from 'axios'
function DataApi({ searchTerm }) {
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(false)
const [error, setError] = useState()
useEffect(() => {
axios
.get('https://jsonplaceholder.typicode.com/posts')
.then(res => {
setUsers(res.data);
console.log(res.data);
setLoading(true);
})
.catch(error => {
console.log(error);
setError('Error retrieving data');
});
}, []);
return (
<div>
<div>
{
!loading ?
<h1>...Loading</h1>
:
users.length > 0 && users.filter((item) =>
(searchTerm === '') ? item :
(item.title.toLowerCase().includes(searchTerm.toLocaleLowerCase())) ? item :
// <h1>search result not found</h1>
null
).map((item) => {
return (
<ul key={item.id}>
<li>Name: {item.id}</li>
<li>Title: {item.title}</li>
<li>Body: {item.body}</li>
</ul>
)}
)
}
{
error ? <h1>{error}</h1> : null
}
</div>
</div>
)
}
export default DataApi;
I have made a search field in which user can search the name of the person. If user does not get the searched name then there should be a message come that search result not found. I tried to implement it using if-else (ternary operator) & put the message into else part but it is not working. When I put null instead of search result not found then it works perfectly but I am not able to show the message then. But if I put search result not found instead of null then nothing works, not even filter functionality. Can you guys please help me? Thank you in advancve.
You can simply check the length of user and move the filter method to the useEffect and show a message
import React, { useState, useEffect } from "react";
import axios from "axios";
function DataApi({ searchTerm }) {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const [searchTermTest, setsearchTermTest] = useState();
function handleChange(event) {
setsearchTermTest(event.target.value);
}
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then((res) => {
const data = res.data;
const filteredData = data.filter((dat) =>
dat.title.includes(searchTermTest === undefined ? "" : searchTermTest)
);
setUsers(filteredData);
setLoading(true);
})
.catch((error) => {
console.log("errr", error);
setError("Error retrieving data");
});
}, [searchTermTest]);
return (
<div>
<input type="text" onChange={handleChange} />
<div>
{!loading ? (
<h1>...Loading</h1>
) : (
users.length > 0 &&
users.map((item) => {
return (
<ul key={item.id}>
<li>Name: {item.id}</li>
<li>Title: {item.title}</li>
<li>Body: {item.body}</li>
</ul>
);
})
)}
{users.length === 0 && loading ? <h1>search result not found</h1> : ""}
{error ? <h1>{error}</h1> : null}
</div>
</div>
);
}
export default DataApi;
{users.length === 0 && loading ? <h1>search result not found</h1> : ""}
I have made it in codesandbox
Codesandbox link here
In Array.filter() method you need to return true/false value, that's how it works.
Modified the code and added the renderUser function to take care of user data filter.
DataApi function
function DataApi({ searchTerm }) {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const [searchTermTest, setsearchTermTest] = useState();
function handleChange(event) {
setsearchTermTest(event.target.value);
}
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then((res) => {
const data = res.data;
const filteredData = data.filter((dat) =>
dat.title.includes(searchTermTest === undefined ? "" : searchTermTest)
);
setUsers(filteredData);
setLoading(true);
})
.catch((error) => {
console.log("errr", error);
setError("Error retrieving data");
});
}, [searchTermTest]);
return (
<div>
<input type="text" onChange={handleChange} />
<div>
{!loading ? (
<h1>...Loading</h1>
) : (
users.length > 0 && renderUsers(users, searchTerm) // updated here...
)}
{error ? <h1>{error}</h1> : null}
</div>
</div>
);
}
renderUsers function
const renderUsers = (users, searchTerm) => {
const filteredUsers = users.filter((item) => {
console.log(item.title);
return searchTerm === ""
? true
: item.title.toLowerCase().includes(searchTerm.toLocaleLowerCase())
? true
: false;
});
return filteredUsers.length > 0 ? (
filteredUsers.map((item) => {
return (
<ul key={item.id}>
<li>Name: {item.id}</li>
<li>Title: {item.title}</li>
<li>Body: {item.body}</li>
</ul>
);
})
) : (
<h1>search result not found</h1>
);
};
export default DataApi;

TypeError: Cannot read property 'params' of undefined for updating categories

So basically I'm trying to create a code that allows me to update the slug with the use of params.
Don't know why My code throws this error.
"TypeError: Cannot read property 'params' of undefined in react".
I tried replacing
useEffect(() => {
loadCategory();
}, []);
with
useEffect(() => {
if(match.params.slug) loadOrders()
}, [match.params.slug])
but it still didn't work.
This is the code I wrote.
import React, { useState, useEffect } from "react";
import {
HistoryContainer,
HistoryBg,
TextContainer2,
TextContainer3,
Text,
CatForm,
FormLabel,
FormControl,
ButtonPrimary,
} from "./CategoryUpdateElements";
import AdminNav from "../AdminNav/index";
import { toast } from "react-toastify";
import { useSelector } from "react-redux";
import { getCategory, updateCategory } from "../../../functions/category";
const CategoryUpdate = ({ history, match }) => {
const { user } = useSelector((state) => ({ ...state }));
const [name, setName] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
loadCategory();
}, []);
const loadCategory = () =>
getCategory(match.params.slug).then((c) => setName(c.data.name));
const handleSubmit = (e) => {
e.preventDefault();
// console.log(name);
setLoading(true);
updateCategory(match.params.slug, { name }, user.token)
.then((res) => {
// console.log(res)
setLoading(false);
setName("");
toast.success(`"${res.data.name}" is updated`);
history.push("/admin/category");
})
.catch((err) => {
console.log(err);
setLoading(false);
if (err.response.status === 400) toast.error(err.response.data);
});
};
return (
<>
<HistoryContainer>
<HistoryBg>
<AdminNav />
<TextContainer2>
<TextContainer3>
{loading ? <Text>Loading..</Text> : <Text>Update category</Text>}
<CatForm onSubmit={handleSubmit}>
<FormLabel>Name</FormLabel>
<FormControl
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
autoFocus
required
/>
<ButtonPrimary>Save</ButtonPrimary>
</CatForm>
</TextContainer3>
</TextContainer2>
</HistoryBg>
</HistoryContainer>
</>
);
};
export default CategoryUpdate;
UPDATE:
To add context to this problem. This code lets me update the name of the slug, but the TypeError doesn't let me follow through with this haha. I was actually following a tutorial regarding this and obviously, his code works. I was sure that I was following it properly as I wrote the code exactly like his but the only difference is my ui.
I also tried console logging match and after checking it out, what I saw was "undefined" which is not surprising.. It should have shown me the slug but instead it gave me "undefined".
This is his code which allows him to update his slug.
import React, { useState, useEffect } from "react";
import AdminNav from "../../../components/nav/AdminNav";
import { toast } from "react-toastify";
import { useSelector } from "react-redux";
import { getCategory, updateCategory } from "../../../functions/category";
const CategoryUpdate = ({ history, match }) => {
const { user } = useSelector((state) => ({ ...state }));
const [name, setName] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
loadCategory();
}, []);
const loadCategory = () =>
getCategory(match.params.slug).then((c) => setName(c.data.name));
const handleSubmit = (e) => {
e.preventDefault();
// console.log(name);
setLoading(true);
updateCategory(match.params.slug, { name }, user.token)
.then((res) => {
// console.log(res)
setLoading(false);
setName("");
toast.success(`"${res.data.name}" is updated`);
history.push("/admin/category");
})
.catch((err) => {
console.log(err);
setLoading(false);
if (err.response.status === 400) toast.error(err.response.data);
});
};
const categoryForm = () => (
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>Name</label>
<input
type="text"
className="form-control"
onChange={(e) => setName(e.target.value)}
value={name}
autoFocus
required
/>
<br />
<button className="btn btn-outline-primary">Save</button>
</div>
</form>
);
return (
<div className="container-fluid">
<div className="row">
<div className="col-md-2">
<AdminNav />
</div>
<div className="col">
{loading ? (
<h4 className="text-danger">Loading..</h4>
) : (
<h4>Update category</h4>
)}
{categoryForm()}
<hr />
</div>
</div>
</div>
);
};
export default CategoryUpdate;
Still new to coding. Hope you guys can help me with this ^_^
I think your problem with match which is getting as the props. If you are having trouble with handle match props please try
useRouteMatch instaed.
import { useRouteMatch } from "react-router-dom";
function YourComponent() {
let match = useRouteMatch();
// Do whatever you want with the match...
return <div />;
}
I think this is more convinent to use.
For more examples

Duplicate keys in React, can't solve the issue. Encountered two children with the same key

Error:
Warning: Encountered two children with the same key, 5e0611d77833da1668feade1. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
Here on this picture https://prnt.sc/qgfymk I have created 2 blogs. Delete button is working fine. I'm sending via axios to HTTP delete request using mongoose and MongoDB as my database.
But when I start to click on like button check what happens. https://prnt.sc/qgg32o
It removes my other blog post and copies one with the same name and id. The issue here is that I have different IDs but somehow when I press LIKE button it gives me another ID.
I'll give you code for both PUT request in backend and frontend for incrementLikes, I really don't know what is going on.
controllers/blogs.js (backend)
blogsRouter.put('/:id', async (request, response, next) => {
const body = request.body
const blogs = {
title:body.title,
author: body.author,
url:body.url,
likes: body.likes
}
try {
const updatedBlog = await Blog.findOneAndUpdate(request.params.id, blogs, {
new: true
})
response.json(updatedBlog.toJSON())
} catch (exception) {
next(exception)
}
})
App.js
import React, { useState, useEffect } from 'react';
import './App.css';
import Blog from './components/Blog';
import LoginForm from './components/LoginForm'
import BlogForm from './components/BlogForm'
import Notification from './components/Notification'
import loginService from './services/login';
import blogService from './services/blogs';
const App = () => {
const [blogs, setBlogs] = useState([])
const [user, setUser] = useState(null)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [errorMessage, setErrorMessage] = useState(null)
// states for blog creation
const [title, setTitle] = useState('')
const [author, setAuthor] = useState('')
const [url, setUrl] = useState('')
useEffect(() => {
console.log('effect')
blogService
.getAll()
.then(response => {
console.log('promise fulfiled')
setBlogs(response.data)
})
.catch(error => {
console.log('response', error.response)
console.log('error')
})
}, [])
useEffect(() => {
const loggedUserJSON = window.localStorage.getItem('loggedBlogUser')
if (loggedUserJSON) {
const user = JSON.parse(loggedUserJSON)
setUser(user)
blogService.setToken(user.token)
}
}, [])
//put request
***const incrementLike = id => {
const blog = blogs.find(b => b.id === id)
console.log('blog id', blog)
const voteLike = {...blog, likes: blog.likes + 1}
blogService
.update(id, voteLike)
.then(returnedBlog => {
setBlogs(blogs.map(blog => blog.id !== id ? blog : returnedBlog))
})
.catch(error => {
setErrorMessage(
`Blog was already removed from server`
)
setTimeout(() => {
setErrorMessage(null)
}, 5000)
})
}***
//login
const handleLogin = async (e) => {
e.preventDefault()
try {
const user = await loginService.login({username, password})
window.localStorage.setItem('loggedBlogUser', JSON.stringify(user))
setUser(user)
setUsername('')
setPassword('')
console.log('success')
} catch (exception) {
setErrorMessage('wrong credentials')
setTimeout(() => {
setErrorMessage(null)
}, 5000)
console.log('baaad')
}
}
const deleteBlogId = (id) => {
console.log('deleted blog')
blogService
.del(id)
.then(response => {
setBlogs(blogs.filter(blog => blog.id !== id))
})
.catch(error => {
console.log(error.response);
})
}
const handleCreateBlog = async (e) => {
e.preventDefault()
const newBlogs = {
title: title,
author: author,
url: url,
date: new Date()
}
blogService
.create(newBlogs)
.then(returnedBlog => {
setBlogs(blogs.concat(returnedBlog))
setTitle('')
setAuthor('')
setUrl('')
setErrorMessage(`${author} created new blog with name ${title}`)
setTimeout(() => {
setErrorMessage(null)
}, 5000)
})
}
const loginForm = () => {
return (
<div>
<Notification message={errorMessage}/>
<div>
<LoginForm
username={username}
password={password}
handleUsernameChange={({target}) => setUsername(target.value)}
handlePasswordChange={({target}) => setPassword(target.value)}
handleSubmit={handleLogin}
/>
</div>
</div>
)
}
const handleTitleChange = (event) => {
console.log(event.target.value)
setTitle(event.target.value)
}
const blogForm = () => {
return (
<div>
<BlogForm
title={title}
author={author}
url={url}
handleTitleChange={handleTitleChange}
handleAuthorChange={({target}) => setAuthor(target.value)}
handleUrlChange={({target}) => setUrl(target.value)}
onSubmit={handleCreateBlog}
/>
</div>
)
}
const handleLogout = async () => {
window.localStorage.clear()
setUser(null)
}
const logout = () => {
return (
<div><button type="reset" onClick={handleLogout}>Logout</button></div>
)}
const blogList = () => {
return (
<div>
<h2>Blogs</h2>
<p>{user.name} logged in</p>
{logout()}
{blogs.map(blog =>
<Blog
key={blog.id}
deleteBlog={() => deleteBlogId(blog.id)}
blog={blog}
increment={() => incrementLike(blog.id)} />
)}
</div>
)
}
return (
<div className="App">
{user === null ?
loginForm() :
<div>
<Notification message={errorMessage}/>
{blogForm()}
{blogList()}
</div>
}
</div>
);
}
export default App;
Check the incrementLikes function. I think there is some kind of issue. Button for likies are in component called Blog.js
Blog.js
import React from 'react';
const Blog = ({blog, increment, deleteBlog}) => (
<div>
<button onClick={deleteBlog}>Delete</button>
{blog.title}
{blog.author}
{blog.likes}
<button onClick={increment}>Like</button>
</div>
)
export default Blog
While there shouldn't be 2 blogs with the same ID you can fix the issue at hand by replacing the key from blog.id to the index of the post like this.
<div>
<h2>Blogs</h2>
<p>{user.name} logged in</p>
{logout()}
//change
{blogs.map((blog,index) =>
<Blog
//change
key={index}
deleteBlog={() => deleteBlogId(blog.id)}
blog={blog}
increment={() => incrementLike(blog.id)} />
)}
</div>
I added //change to the lines I changed.
You can just use something like uuid for this which will generate a unique ID.
import uuid from "uuid";
<>
<h2>Blogs</h2>
<p>{user.name} logged in</p>
{logout()}
{blogs.map((blog,index) =>
<Blog
key={uuid.v4()}
deleteBlog={() => deleteBlogId(blog.id)}
blog={blog}
increment={() => incrementLike(blog.id)} />
)}
</>

Categories