I have React pages (BlogContent & RelatedBlog),
"BlogContent" : To show the article content for the author and at the bottom of the page are his other articles. "RelatedBlog": Display the other article belonging to same author that the user want to read
When a user views blog content, he can see below more blogs for the author. When the user clicks on the article he wants to read, the slug on Url changes but the content does not change until the user refreshes the page, so the user must refresh the page every time he wants to see all related blogs for the author.
I think the reason the blog page require refreshes every time is because useEffect() , but I don't know what is the trick to fix it
Here's my code to page BlogContent:
import React, { useEffect, useState } from 'react';
import { useParams } from "react-router-dom";
import { ClockCircleOutlined } from '@ant-design/icons';
import { Image, Layout, Typography } from 'antd';
import axiosInstance from '../../axios';
import { RelatedBlog } from './RelatedBlog';
export const BlogContent = () => {
const { slug } = useParams(); //to show blog based on slug
const [data, setData] = useState({ posts: [] });
useEffect(() => {
axiosInstance.get(slug).then((res) => {
setData({ posts: res.data });
});
}, [setData]);
const { Content } = Layout;
const { Title, Paragraph, Text } = Typography;
let AuthorBlog = data.posts.author // Extract the author name and pass them all as prop
return (
<>
<Layout>
<Content>
<Image src={data.posts.image} preview={false}/>
<Layout>
<Typography>
<Title level={2}>{data.posts.title}</Title>
<Text>Created By: <Text strong className='writer' {data.posts.author}</Text></Text>
<div className='dateDiv'><ClockCircleOutlined style={{
color: 'rgb(59, 110, 145)',
fontSize: '1.2rem', paddingRight: '0.6rem'}} />
<Text className='date'>Published on:{' '} {new Date(data.posts.published).toDateString()}</Text></div>
</Typography>
</Layout>
<Layout>
<Typography>
<Paragraph>{data.posts.content}</Paragraph>
</Typography>
</Layout>
</Content>
</Layout>
<RelatedBlog AuthorBlog={AuthorBlog}/> // put author as prop to render all blogs for athor
</>
);
};
and here for RelatedBlog:this botton to let user go to other article<Link to={/post/${blog.slug}
}>Continue reading
import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import axiosInstance from '../../axios';
export const RelatedBlog = (props) => {
const { AuthorBlog } = props;
const [appState, setAppState] = useState([]);
useEffect(() => {
axiosInstance.get("/").then((res) => {
const allBlogs = res.data;
setAppState(allBlogs);
});
}, [setAppState]);
// Fetch all blogs and filter to just display blogs' author
const filterAuthor = appState.filter((item) => item.author === AuthorBlog) ;
console.log("The Author", filterAuthor);
return (
<section className='container'>
<div>
<h2 className="pt-5">more related</h2>
</div>
<p style={{marginLeft:'22px',marginTop:'35px', fontWeight:'bold', fontSize:'20px'}}><strong>Total blogs: </strong>{filterAuthor.length}</p>
<div className='row'>
{filterAuthor.map((blog) => (
<div key={blog.id} className="m-2 text-center col-lg-3 col-md-3">
<div className='card'>
<div className="card-body">
<h5>{blog.title.substr(0, 35)}...</h5>
<p>{blog.content.substr(0, 150)}...</p>
// here user click on botton to go to other article
<Link to={`/post/${blog.slug}`} style={{color:'rgb(59, 110, 145)', fontSize:'1rem'}}>Continue reading...</Link>
</div>
</div>
</div>
))}
</div>
</section>
)}
App.js:
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.bundle';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import './App.css';
import { Navbar } from './components/Navbar';
import Home from './components/pages/Home';
import {BooksCard} from './components/pages/Card/BooksCard';
import {Footer} from './components/Footer';
import {ContactPage} from './components/pages/ContactPage';
import { Articles } from './components/pages/ArticlePage/Articles';
import Admin from './components/pages/Dashboard/Admin';
import {Create} from './components/pages/Dashboard/Create';
import {Edit} from './components/pages/Dashboard/Edit';
import {Delete} from './components/pages/Dashboard/Delete';
import { Profile } from './components/pages/Profile';
import {Error} from './Error';
import { BlogContent } from './components/Home/BlogContent';
import { About } from './components/Home/About';
import Login from './components/pages/Forms/Login';
import Register from './components/pages/Forms/Register';
import Logout from './components/pages/Forms/Logout';
import ResetPassword from './components/pages/Forms/ResetPassword';
import ResetPasswordConfirm from './components/pages/Forms/ResetPasswordConfirm';
import Search from 'antd/lib/input/Search';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
function App() {
return (
<>
<ToastContainer hideProgressBar={false} position="top-center" autoClose={3000} closeOnClick />
<Router>
<Navbar />
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="/home" element={<Home />} />
<Route path="/book" element={<BooksCard />} />
<Route path="/contact" element={<ContactPage />} />
<Route path="/post/:slug" element={<BlogContent />} />
<Route path="/articles" element={<Articles />} />
<Route path="/search" element={<Search />}/>
<Route exact path="/dashboard" element={<Admin />} />
<Route exact path="/dashboard/create" element={<Create />} />
<Route exact path="/dashboard/edit/:id" element={<Edit />} />
<Route exact path="/dashboard/delete/:id" element={<Delete />} />
<Route path="/about" element={<About />} />
<Route path="/profile" element={<Profile />} />
<Route path="/login" element={<Login />}/>
<Route path="register" element={<Register />} />
<Route path="/logout" element={<Logout />}/>
<Route exact path="/reset-password" element={<ResetPassword />} />
<Route exact path='/password/reset/confirm/:uid/:token' element={<ResetPasswordConfirm />} />
<Route path="/*" element={<Error />} />
</Routes>
<Footer />
</Router>
</>
);
}
export default App;
Thanks
CodePudding user response:
As I've written in the comments - adding slug
to the dependency array of your useEffect
fixed the problem.
Why is that?
Dependency array in useEffect
hook is used to rerun the hook when one of these variables changes. In your case, changing the url, changes the slug so the component should load new data.
I would even remove setData
from this array, because it doesn't do anything as useState
setters don't ever change.
useEffect(() => {
laxiosInstance.get(slug).then((res) => {
setData({ posts: res.data });
});
}, [slug]);