Home > other >  How to force React page to scroll up when user id is changing in route?
How to force React page to scroll up when user id is changing in route?

Time:12-17

I have couple of react components and this question refers to specifically to two components: UserDetails and User, inside UserDetails I am rendering friends of the user, each of them is component User, so when I click one of their friend, in route, user id is changing but in reality I am rendering same component: UserDetails, and I am fetching data of this user but page is not scrolling up, can I fix it somehow?

Here is UserDetails

import React, {useEffect, useState} from 'react';
import {useParams} from 'react-router-dom';
import { Link } from 'react-router-dom';
import User from './User';
import { useDispatch, useSelector } from 'react-redux';
import { setSelectedUser, removeUser, setSelectedUsersHistory, setUserFriends, setFriendsPage, setFriendsLoading } from '../redux/actions/actions';
import '../styles/UserDetails.css';

export const UserDetails = () => {
    const selectedUser = useSelector(state => state.setSelectedUserReducer);
    const selectedUsersHistory = useSelector(state => state.setSelectedUsersHistoryReducer);
    const userFriends = useSelector(state => state.setUserFriendsReducer);
    const friendsPage = useSelector(state => state.setFriendsPageReducer);
    const friendsLoading = useSelector(state => state.setFriendsLoadingReducer);
    const [dynamicId, setDynamicId] = useState('');
    const dispatch = useDispatch();
    const {userId} = useParams();
    const fetchUserDetails = () => {
        fetch(`${url}/${userId}`)
            .then(res => res.json())
            .then(data => {
                 dispatch(setSelectedUser(data));
                 setDynamicId(userId)
              }
            )
            .catch(err => console.log('Error message: ', err))
    }

    const fetchUserFriends = () => {
        dispatch(setFriendsLoading(true));
        fetch(`${url}/${userId}/friends/${friendsPage}/15`)
            .then(res => res.json())
            .then(data => {         
                    dispatch(setUserFriends( data.list.filter(el => {
                        return el.id.toString() !== userId
                    })))
            })
            .catch(err => console.log('Error message: ', err))
            .finally(() => {
                dispatch(setFriendsLoading(false))
            })
    }

    useEffect(() => {
        if(userId && userId!=='') fetchUserDetails();
        
        return () => {
            dispatch(removeUser())
        }
    }, [userId])

    useEffect(() => {
        fetchUserFriends()
    }, [friendsPage])
  
      const handleScroll = () => {
          dispatch(setFriendsPage());
      }
  
      window.onscroll = function () {
          if(window.innerHeight   document.documentElement.scrollTop === document.documentElement.offsetHeight) {
              handleScroll();
          }
      }


    return (
        <div className="userDetails">
            {
                Object.keys(selectedUser).length === 0 ? (
                    <div>Loading...</div>
                ) : (
                <div className="user-about">
                <div className="user-details-image">
                    <img src={selectedUser.imageUrl} alt="user-image" />
                </div>

                <div className="user-info">
                    <fieldset>
                        <legend>Info</legend>
                        <div className="row1">
                            <h3>
                                 <span>{selectedUser.prefix} </span>
                                 <span>{selectedUser.name} </span>
                                 <span>{selectedUser.lastName} </span>
                            </h3>
                        </div>

                        <div className="row2">
                            <div className="personal-details">
                                <span className="email-label label">
                                    Email:
                                </span>

                                <span> </span>

                                <span className="email-data">
                                    {selectedUser.email}
                                </span>
                            </div>
                            <div className="personal-details">
                               <span className="ip-address-data label">
                                    IP Address: 
                                </span> 

                                <span> </span>

                                <span className="ip-address-data">
                                    {selectedUser.ip}
                                </span>
                            </div>
                            <div className="personal-details">
                            <span className="job-area-label label">
                                    Job Area:
                                </span>

                                <span> </span>

                                <span className="job-area-data">
                                    {selectedUser.jobArea}
                                </span>
                            </div>
                            <div className="personal-details">
                            <span className="job-type-label label">
                                    Job Type:
                                </span>

                                <span> </span>

                                <span className="job-type-data">
                                    {selectedUser.jobType}
                                </span>
                            </div>
                        </div>
                    </fieldset>
                </div>

                <div className="user-address">
                    <fieldset>
                        <legend>Address</legend>
                        <div className="address-info">
                                <h3>
                                    <span>{selectedUser.company.name}</span>
                                    <span>{selectedUser.company.suffix}</span>
                                </h3>

                                <div className="personal-details">
                                    <span className="city-label label">
                                        City:
                                    </span>

                                    <span> </span>

                                    <span className="city-data">
                                        {selectedUser.address.city}
                                    </span>
                                </div>

                                <div className="personal-details">
                                    <span className="country-label label">
                                        Country:
                                    </span>

                                    <span> </span>

                                    <span className="country-data">
                                        {selectedUser.address.country}
                                    </span>
                                </div>

                                <div className="personal-details">
                                    <span className="state-label label">
                                        State:
                                    </span>

                                    <span> </span>

                                    <span className="state-data">
                                        {selectedUser.address.state}
                                    </span>
                                </div>

                                <div className="personal-details">
                                    <span className="street-label label">
                                        Street Address:
                                    </span>

                                    <span> </span>

                                    <span className="street-data">
                                        {selectedUser.address.streetAddress}
                                    </span>
                                </div>

                                <div className="personal-details">
                                    <span className="zip-label label">
                                        ZIP:
                                    </span>

                                    <span> </span>

                                    <span className="zip-data">
                                        {selectedUser.address.zipCode}
                                    </span>
                                </div>
                        </div>
                    </fieldset>
                </div>
            </div>
                )
            }

            <div className="friends-list">
                    {
                        userFriends ? (
                            userFriends.map((friend, index) => (
                                <Link key={friend.id} to={`/user/${friend.id}`}>
                                    <User name={friend.name} lastName={friend.lastName} prefix={friend.prefix} title={friend.title} img={`${friend.imageUrl}/${friend.id}`}/>
                                </Link>
                            ))
                        ) : (
                             <div> Loading... </div>
                        )
                    }


                    {
                        friendsLoading ? <h1>Loaidng...</h1> : ''
                    }
            </div>
        </div>
    )
}

export default UserDetails;

Here is the User component:

import React, {useEffect} from 'react';
import '../styles/User.css';

const User = ({name, lastName, prefix, title, img}) => {
    return (
        <div className="user">
            <div className="user-image">
                <img src={`${img}/${Math.random()}`} alt="user-image" />
            </div>

            <div className="user-name">
                <span>{prefix} </span>
                <span>{name} </span>
                <span>{lastName} </span>
            </div>

            <div className="user-position">
                <span>{title}</span>
            </div>
        </div>
    )
}

export default React.memo(User);

CodePudding user response:

You just need to use useMemo or useEffect to make the window scroll to the top when a variable's value (userId in this case) has been modified/changed. For example:

import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { Link } from "react-router-dom";
import User from "./User";
import { useDispatch, useSelector } from "react-redux";
import {
  setSelectedUser,
  removeUser,
  setSelectedUsersHistory,
  setUserFriends,
  setFriendsPage,
  setFriendsLoading,
} from "../redux/actions/actions";
import "../styles/UserDetails.css";

export const UserDetails = () => {
  const selectedUser = useSelector((state) => state.setSelectedUserReducer);
  const selectedUsersHistory = useSelector(
    (state) => state.setSelectedUsersHistoryReducer
  );
  const userFriends = useSelector((state) => state.setUserFriendsReducer);
  const friendsPage = useSelector((state) => state.setFriendsPageReducer);
  const friendsLoading = useSelector((state) => state.setFriendsLoadingReducer);
  const [dynamicId, setDynamicId] = useState("");
  const dispatch = useDispatch();
  const { userId } = useParams();
  const fetchUserDetails = () => {
    fetch(`${url}/${userId}`)
      .then((res) => res.json())
      .then((data) => {
        dispatch(setSelectedUser(data));
        setDynamicId(userId);
      })
      .catch((err) => console.log("Error message: ", err));
  };

  const fetchUserFriends = () => {
    dispatch(setFriendsLoading(true));
    fetch(`${url}/${userId}/friends/${friendsPage}/15`)
      .then((res) => res.json())
      .then((data) => {
        dispatch(
          setUserFriends(
            data.list.filter((el) => {
              return el.id.toString() !== userId;
            })
          )
        );
      })
      .catch((err) => console.log("Error message: ", err))
      .finally(() => {
        dispatch(setFriendsLoading(false));
      });
  };

  useEffect(() => {
    if (userId && userId !== "") {
      fetchUserDetails();
      window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
    }

    return () => {
      dispatch(removeUser());
    };
  }, [userId]);

  useEffect(() => {
    fetchUserFriends();
  }, [friendsPage]);

  const handleScroll = () => {
    dispatch(setFriendsPage());
  };

  window.onscroll = function () {
    if (
      window.innerHeight   document.documentElement.scrollTop ===
      document.documentElement.offsetHeight
    ) {
      handleScroll();
    }
  };

  return (
    <div className="userDetails">
      {Object.keys(selectedUser).length === 0 ? (
        <div>Loading...</div>
      ) : (
        <div className="user-about">
          <div className="user-details-image">
            <img src={selectedUser.imageUrl} alt="user-image" />
          </div>

          <div className="user-info">
            <fieldset>
              <legend>Info</legend>
              <div className="row1">
                <h3>
                  <span>{selectedUser.prefix} </span>
                  <span>{selectedUser.name} </span>
                  <span>{selectedUser.lastName} </span>
                </h3>
              </div>

              <div className="row2">
                <div className="personal-details">
                  <span className="email-label label">Email:</span>

                  <span> </span>

                  <span className="email-data">{selectedUser.email}</span>
                </div>
                <div className="personal-details">
                  <span className="ip-address-data label">IP Address:</span>

                  <span> </span>

                  <span className="ip-address-data">{selectedUser.ip}</span>
                </div>
                <div className="personal-details">
                  <span className="job-area-label label">Job Area:</span>

                  <span> </span>

                  <span className="job-area-data">{selectedUser.jobArea}</span>
                </div>
                <div className="personal-details">
                  <span className="job-type-label label">Job Type:</span>

                  <span> </span>

                  <span className="job-type-data">{selectedUser.jobType}</span>
                </div>
              </div>
            </fieldset>
          </div>

          <div className="user-address">
            <fieldset>
              <legend>Address</legend>
              <div className="address-info">
                <h3>
                  <span>{selectedUser.company.name}</span>
                  <span>{selectedUser.company.suffix}</span>
                </h3>

                <div className="personal-details">
                  <span className="city-label label">City:</span>

                  <span> </span>

                  <span className="city-data">{selectedUser.address.city}</span>
                </div>

                <div className="personal-details">
                  <span className="country-label label">Country:</span>

                  <span> </span>

                  <span className="country-data">
                    {selectedUser.address.country}
                  </span>
                </div>

                <div className="personal-details">
                  <span className="state-label label">State:</span>

                  <span> </span>

                  <span className="state-data">
                    {selectedUser.address.state}
                  </span>
                </div>

                <div className="personal-details">
                  <span className="street-label label">Street Address:</span>

                  <span> </span>

                  <span className="street-data">
                    {selectedUser.address.streetAddress}
                  </span>
                </div>

                <div className="personal-details">
                  <span className="zip-label label">ZIP:</span>

                  <span> </span>

                  <span className="zip-data">
                    {selectedUser.address.zipCode}
                  </span>
                </div>
              </div>
            </fieldset>
          </div>
        </div>
      )}

      <div className="friends-list">
        {userFriends ? (
          userFriends.map((friend, index) => (
            <Link key={friend.id} to={`/user/${friend.id}`}>
              <User
                name={friend.name}
                lastName={friend.lastName}
                prefix={friend.prefix}
                title={friend.title}
                img={`${friend.imageUrl}/${friend.id}`}
              />
            </Link>
          ))
        ) : (
          <div> Loading... </div>
        )}

        {friendsLoading ? <h1>Loaidng...</h1> : ""}
      </div>
    </div>
  );
};

export default UserDetails;
  • Related