0

"myGroups" is a context variable. In my context store, I am fetching data from a database and populating this "myGroups" variable. So initially it contains only an empty array, after some time it contains an array of objects. e.g. [{id: "", data: ""}]

I want to render these groups. So I am mapping through the myGroups variable, and trying to render them.

But the problem is that even after context updating, my component does not re-render. I have console logged and seen that the fetching of data works absolutely fine, though it takes some time to do so.

Does changing the context does not rerender it's consumer? Why is the component not rerendering? It would be of great help if you can provide some solution. Thanks in Advance.

Here is my code.

import React, { useContext, useEffect, useState } from 'react';

import "../css/MyGroups.css";
import GroupCard from './GroupCard';
import { GlobalContext } from '../context/GlobalState';

const MyGroups = () => {
    const { myGroups } = useContext(GlobalContext);

    useEffect(() => console.log(myGroups), [myGroups]); // Debugging 

    return (
        <div className="my__groups">
            <h1 className="my__groups__heading">My Groups</h1>
            <div className="my__groups__underline"></div>
            <div className="my__groups__grid__container">
                {
                    myGroups.map(({id, data}) => (
                        <GroupCard
                            key={id}
                            name={data.name}
                            image={data.image} 
                        />
                    ))
                }
            </div>
        </div>
    )
}

export default MyGroups

This is what I get on the console when the context changes: Console log image

My Global Provider:

<GlobalProvider>
      <BrowserRouter>
        <Main />
      </BrowserRouter>
</GlobalProvider>

The MyGroups Component is a descendant of the Main Component.

Edit 1: Fetch Function of my Store

function fetchGroupsFromDatabase(id) {
        let myGroups = [];
        db.collection("users").doc(id).get() // Fetch user details with given id 
            .then(doc => {
                doc.data().groupIDs.map(groupID => { // Fetch all group IDs of the user
                    db.collection("groups").doc(groupID).get() // Fetch all the groups 
                        .then(doc => {
                            myGroups.push({id: doc.id, data: doc.data()})
                        })
                })
            })
            .then(() => {
                const action = {
                    type: FETCH_GROUPS_FROM_DATABASE,
                    payload: myGroups
                };
                dispatch(action);
            })
    }

Edit 2: Reducer

const Reducer = (state, action) => {
    switch(action.type) {
        case FETCH_GROUPS_FROM_DATABASE:
            return {
                ...state, 
                myGroups: action.payload
            };
        default:
            return state;
    }
}

export default Reducer;

2
  • 2
    You really don't need to save myGroups inside the local state of your component. Whenever something in the Context gets updated, all the components, that consume that context, are re-rendered. So, using useState to save some data from the Context is completely unnecessary. Commented Jan 17, 2021 at 11:07
  • can you share your GlobalContext? Commented Jan 17, 2021 at 11:08

1 Answer 1

1

As Yousaf said, not need to using useState and useEffect. You can use context in two different way

first:

const MyGroups = () => (
  <GlobalContext.Consumer>
    {({ myGroups }) => (
         <div className="my__groups">
            <h1 className="my__groups__heading">My Groups</h1>
            <div className="my__groups__underline"></div>
            <div className="my__groups__grid__container">
                {myGroups.map(({id, data}) => (
                        <GroupCard
                            key={id}
                            name={data.name}
                            image={data.image} 
                        />
                    ))
                }
            </div>
        </div>
    )}
  </GlobalContext.Consumer>
);

second:

const MyGroups = () => {
  const { myGroups } = useContext(GlobalContext);

  return (
    <div className="my__groups">
      <h1 className="my__groups__heading">My Groups</h1>
      <div className="my__groups__underline"></div>
      <div className="my__groups__grid__container">
        {myGroups.map(({ id, data }) => (
          <GroupCard key={id} name={data.name} image={data.image} />
        ))}
      </div>
    </div>
  );
};

Edit: the problem comes from the Fetch Function it based on this answer should be like this:

async function fetchGroupsFromDatabase(id) {
    const doc = await db.collection("users").doc(id).get() // Fetch user details with given id 
    const myGroups = await Promise.all(
        doc.data().groupIDs.map(groupID => // Fetch all group IDs of the user
            db.collection("groups").doc(groupID).get() // Fetch all the groups 
                .then(doc => ({ id: doc.id, data: doc.data() }))
        )
    );
    const action = {
        type: FETCH_GROUPS_FROM_DATABASE,
        payload: myGroups
    };
    dispatch(action);
}
Sign up to request clarification or add additional context in comments.

13 Comments

Followed your syntax...but my component is not re-rendering either on context change or state change...
can you share your GlobalContext? Did you wrap your component inside GlobalContext?
<GlobalProvider> <BrowserRouter> <Main /> </BrowserRouter> </GlobalProvider>
The MyGroups component is a descendant component of the Main component.
I have also shown image of console logs of myGroups context at the last of my question. You can also have a look and inspect that.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.