Home > Enterprise >  When a user clicks on a related blog, Reactjs requires them to refresh page
When a user clicks on a related blog, Reactjs requires them to refresh page

Time:04-14

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]);
  • Related