0

Ive been searching online for a method that refreshed the browser but I cant find anything and Im wondering if its even possible. I have a table that the user can update but when its updated the changes dont show. Any info about browser refreshing would be super helpful or maybe an alternate route for handling my problem:

this is my parent component:

const UserList = ({}) => {
  const [list, setList] = useState([]);
  const [errors, setErrors] = useState();
  const [showPopUp, setShowPopUp] = useState(false);
  const [permission, setPermission] = useState();
  const [adminID, setAdminID] = useState();
  const [successM, setSuccessM] = useState();

 useEffect(() => {
    api.UserManagement.list()
      .then((result) => {
        let list = [];
        if (result) {
          list = result.items;
        }
        setList(list);
      })
      .catch((err) => {
        if (err.status) {
          console.log("error", err, err.status);
          setErrors([err]);
        }
      });
    
}, []);


    const adminUpdate = async (perm, id) => {
        console.log(perm, id);
        if (!perm || !id) {
          return;
        } else {
          try {
           const result = await api.UserManagement.put(id, { permissions: [perm] })
           const tempList = (list || []).map((item) => {
             console.log(list)
             if(item.id = id) {
               item.permissions = [perm]
             }
             return item;
           })
          }catch (e) {
            console.log("error", e)
          }
          
        }
      };

return (
    <>
      {showPopUp && (
        <RolePopUp
          showPopUp={showPopUp}
          setShowPopUp={setShowPopUp}
          adminUpdate={adminUpdate}
          adminID={adminID}
          setPermission={setPermission}
          setSuccessM={setSuccessM}
        />
      )}
..... 
//where the table is sent the list of users to use
 <tbody>
            {!list ? (
              <PageLoadSpinner />
            ) : (
              list.map((item, idx) => (
                <UserCard
                  key={idx}
                  item={item}
                  setShowPopUp={setShowPopUp}
                  showPopUp={showPopUp}
                  adminUpdate={adminUpdate}
                  setAdminID={setAdminID}
                  permission={permission}
                />
              ))
            )}
          </tbody>
        </Table>
      </ContentRow>
)

Im hoping to add my refresh browser method inside the try catch statement in the parent component if the api call succeeds then refresh the browser if not then render an error.I can show the child components if needed.

CourtneyJ
  • 458
  • 6
  • 19
  • In `adminUpdate` you don't actually update the state. – kunquan Jan 16 '21 at 22:10
  • Yea I know but it is where the api call is made to change the users info in the DB so my thinking is if that call is successful I can then refresh the browser so that changes are reflected. Does that make sense? @kunquan – CourtneyJ Jan 16 '21 at 23:45
  • @CourtneyJ The whole point of refreshing a page is to clear the state in most cases. Since you are fetching the data from the list, you need to make sure that the data is being responded back. Try console.logging in the .then() to make sure the data is in fact there and in the corrent JSON array structure to map properly. React is smart, It knows when the state has changed so the page doesnt need to be refreshed to render to the screen. – twominds Jan 16 '21 at 23:50
  • @user67 Okay when i console the result in the useEffect function after I make changes it looks like the list is changed. But for some reason the list doesnt reflect those changes until I refresh the page. Do you know why this could be? – CourtneyJ Jan 16 '21 at 23:55
  • If you make any changes to your database, they won't render or update until the user refreshes the page. Is this the issue you're having? Because there are ways you can fix that behavior. – twominds Jan 17 '21 at 00:02
  • Yes thats my problem! Im not sure how to handle it – CourtneyJ Jan 17 '21 at 00:04
  • @user67 I am still struggling to figure out how to solve this issue. Do you have any guidance? – CourtneyJ Jan 18 '21 at 18:06
  • @CourtneyJ Create a function that compares the client state data to the server data. Compare the client objects IDs from the state data already saved, to the server objects ID's. If any ID doesn't match from the database to the client, you can force another Axios request, or you can render a button to the screen as Twitter does so the user can click and make that request themselves. Don't compare the entire object since this would be very slow. I personally would do this all with redux. To do this the mongoose way; you need good understanding of the aggregation pipeline to compare these ids. – twominds Jan 18 '21 at 21:33
  • I was just thinking, you could also create a boolean update value for each user in the collection that has access to the data. When the database is updated by either a user or automatically, it will set all of the users who aren't authors that have access to the data "update values" to false. This way you can simply query the "update" value every interval you choose. It doesn't cost much. Then you can implement the answer i provided below that compares the state data id's to the db data id's, and have it respond back the data that has not yet been saved to the state. – twominds Jan 19 '21 at 08:34

1 Answers1

0

Let's say your db collection looks like this:

db.collection.items = [
{
  _id: "123"
  item: 123
},
{
  _id: "456"
  item: 456
},
{...more items}
]

And your state looks like this:

const [stateData, setStateData] = useState([{
  _id: "123".
  item: 123
}])

Create a redux action function to update on a timer or by button:

export const getUpdatedData = (state_ids) => {
  axios.post("/example/items", {
    state_ids
  }).then((res) => {
    if (res.status === 200) {
      if (res.data.update) {
        //save updated data to state 
      } else {
        // dont do anything
      }
    }
    save the response to the state
  }).catch((err) => {
    console.log(err)
  })
}

In a route js express file create a route:

// using the aggregation pipeline is much more efficient, these are just simple queries

db.collection.find().then((items) => {
  if (items.length > req.body._ids.length) {
//this unique function compares the db data Ids to the req.body.ids from the client
    const unique = [...new Map(items.map(item => [item[req.body._ids], item])).values()]
    res.status(200).json({update: true, data: unique})
  } else if (
    items.length === req.body._ids.length
  ) {
    res.status(200).json({
update: false
    })
  }

})

Read up on this: https://stackoverflow.com/a/56768137/14849955 but don't use it since the server has to query the data and then filter it, instead, use the aggregation pipeline filters while it's querying. Aggregation more efficient: https://mongoosejs.com/docs/api/aggregate.html#aggregate_Aggregate

If you have any questions feel free to ask.

twominds
  • 1,084
  • 5
  • 20