简体   繁体   中英

refresh user data when changes are made to mongodb

I am new to react and MongoDB, I have this site where the user can log in and look at his detail like name…, coming from the db. I am trying to find a way to update what is shown to the client when a change is made directly from the database, or when a button is clicked refresh user data, so it shows newly updated data from the database. I am using useReducer for authentication of the user and make updates to him from the client, but I can't find a way to update the data shown to the client. If changes are made directly from the db, the user has to log out and log back in to see the updated version of them. Again, I am very new to useReducer and have only managed to barely make it work from what I could find, but I can't find this particular problem I have anywhere. If someone could help, I greatly appreciate it. Tell me if you need more context or any other file.

My AuthContext file with useReducer

import React from "react";
import { createContext, useEffect, useReducer } from "react";

const INITIAL_STATE = {
  user: JSON.parse(localStorage.getItem("user")) || null,
  loading: false,
  error: null,
};

export const AuthContext = createContext(INITIAL_STATE);

const AuthReducer = (state, action) => {
  switch (action.type) {
    case "LOGIN_START":
      return {
        user: null,
        loading: true,
        error: null,
      };
    case "LOGIN_SUCCESS":
      return {
        user: action.payload,
        loading: false,
        error: null,
      };
    case "LOGIN_FAILURE":
      return {
        user: null,
        loading: false,
        error: action.payload,
      };
    case "LOGOUT":
      return {
        user: null,
        loading: false,
        error: null,
      };
    case "UPDATE_USER_DATE":
      const updatedUser = { ...state.user };
      updatedUser.activeUntil = action.payload;
      return {
        ...state,
        user: updatedUser,
      };
    case "UPDATE_USER":
      const updateUser = { ...state.user };
      return {
        ...state,
        user: updateUser,
      };
    default:
      return state;
  }
};

export const AuthContextProvider = ({ children }) => {
  const [state, dispatch] = useReducer(AuthReducer, INITIAL_STATE);

  useEffect(() => {
    localStorage.setItem("user", JSON.stringify(state.user));
  }, [state.user]);

  return (
    <AuthContext.Provider
      value={{
        user: state.user,
        loading: state.loading,
        error: state.error,
        dispatch,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

where i am trying to make the update happen

import React, { useContext } from "react";
import { useState } from "react";
import useFetch from "../../hooks/useFetch";
import Footer from "../../components/OutFooter";
import Navbar from "../../components/OutNavbar";
import Sidebar from "../../components/OutSidebar";
import {
  ContractContainer,
  HeadingContainer,
  TypeH1,
  ActiveUntil,
  MonthlyWrapper,
  MonthlyContainer,
  MonthNumber,
  Price,
  Navbarback,
} from "./userinfoElements";
import { AuthContext } from "../../context/AuthContext";
import { Navigate } from "react-router-dom";
import moment from "moment";
import axios from "axios";

const Userinfo = () => {
  // for nav bars
  const [isOpen, setIsOpen] = useState(false);

  // set state to true if false
  const toggle = () => {
    setIsOpen(!isOpen);
  };

  const { user, dispatch } = useContext(AuthContext);
  if (!user) {
    return <Navigate to="/" />;
  }

  const { data } = useFetch(`/contracts/${user.contractType}`);

  let dateFormat = moment(user.activeUntil).format("DD/MMMM/yyyy");

  const update1Month = async () => {
    try {
      let newDate = moment(user.activeUntil).add(30, "days");
      dateFormat = newDate.format("DD/MMMM/yyyy");
      await axios.put(`/activedate/${user.namekey}`, {
        activeUntil: newDate,
      });
      dispatch({ type: "UPDATE_USER_DATE", payload: newDate });
    } catch (err) {
      console.log(err);
    }
  };



  const update3Month = async () => {
    try {
      let newDate = moment(user.activeUntil).add(90, "days");
      dateFormat = newDate.format("DD/MMMM/yyyy");
      await axios.put(`/activedate/${user.namekey}`, {
        activeUntil: newDate,
      });
      dispatch({ type: "UPDATE_USER_DATE", payload: newDate });
    } catch (err) {
      console.log(err);
    }
  };
  const update6Month = async () => {
    try {
      let newDate = moment(user.activeUntil).add(180, "days");
      dateFormat = newDate.format("DD/MMMM/yyyy");
      await axios.put(`/activedate/${user.namekey}`, {
        activeUntil: newDate,
      });
      dispatch({ type: "UPDATE_USER_DATE", payload: newDate });
    } catch (err) {
      console.log(err);
    }
  };
  const update12Month = async () => {
    try {
      let newDate = moment(user.activeUntil).add(365, "days");
      dateFormat = newDate.format("DD/MMMM/yyyy");
      await axios.put(`/activedate/${user.namekey}`, {
        activeUntil: newDate,
      });
      dispatch({ type: "UPDATE_USER_DATE", payload: newDate });
    } catch (err) {
      console.log(err);
    }
  };
  const refreshUser = async () => {
    try {
      dispatch({ type: "UPDATE_USER" });
    } catch (err) {
      console.log(err);
    }
  };
  return (
    <>
      <Sidebar isOpen={isOpen} toggle={toggle} />
      {/* navbar for smaller screens*/}
      <Navbar toggle={toggle} />
      <Navbarback /> {/* filling for transparent bacground navbar*/}
      <>
        <ContractContainer>
          <button onClick={refreshUser}>toooo</button>
          <TypeH1>
            Hello {user.fName} {user.lName}!
          </TypeH1>
          <HeadingContainer>
            <TypeH1>{data.contractType}</TypeH1>
            <ActiveUntil>Subscription active until {dateFormat}</ActiveUntil>
          </HeadingContainer>
          <MonthlyWrapper>
            <MonthlyContainer>
              <MonthNumber>1 Month</MonthNumber>
              <Price onClick={update1Month}>{data.month1Price}$</Price>
            </MonthlyContainer>
            <MonthlyContainer>
              <MonthNumber>3 Month</MonthNumber>
              <Price onClick={update3Month}>{data.month3Price}$</Price>
            </MonthlyContainer>
            <MonthlyContainer>
              <MonthNumber>6Month</MonthNumber>
              <Price onClick={update6Month}>{data.month6Price}$</Price>
            </MonthlyContainer>
            <MonthlyContainer>
              <MonthNumber>12Month</MonthNumber>
              <Price onClick={update12Month}>{data.month12Price}$</Price>
            </MonthlyContainer>
          </MonthlyWrapper>
        </ContractContainer>
      </>
      <Footer />
    </>
  );
};

export default Userinfo;

in particular ->

 const refreshUser = async () => {
    try {
      dispatch({ type: "UPDATE_USER" });
    } catch (err) {
      console.log(err);
    }
  }; 

I doubt you can cause a re-render by changing a document directly from the database. However, if you want a refresh button, you can first create a new state

const [refresh, setRefresh] = React.useState(false)

then pass this onClick handler to a refresh button which is in the same component as your user details stuff like

<button onClick = {() => setRefresh(prev => !prev)}>Refresh</button>

After dabbling here and there, I resulted accidentally exactly what I needed. I found that using useEffect I can load a function at the start of the page loading. Accidentally doing this also resulted in updating my local stored user to the one in my database. I changed some things in my context file and added a new controller on api side that posts already stored users. If anyone requires further explanations or examples feel free to ask!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM