0

I'm trying to pass an array of objects to my MenuPage from the App.js. If there's no map, I can consolelog the activities prop I passed. But when I try to run the map I get an error and the console.log can no longer identify the activities prop, but instead I receive multiple console.logs of empty arrays.

Also, is this the correct way so that my activities render dynamically? I used to have the activities state on the MenuPage.js, but whenever I add a new activity, I'd have to refresh in order for the newly added activity to appear. Hence, I decided to try to move it in its parent file which is the App.js.

error message when map

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

Console log of activities prop if no map

{getActivities: Array(5)}
    getActivities: Array(5)
        0: {id: "5e64abc6de157e027c1fc224", name: "Test1", location: "Test1", activityDate: "Test1", description: "Test1", …}
        1: {id: "5e69b103dd9e0b20f8636da9", name: "Test234", location: "Test2", activityDate: "Test2", description: "Test2", …}
        2: {id: "5e6a744eca11a3355cdde03b", name: "test3", location: "test3", activityDate: "test3", description: "test3", …}
        3: {id: "5e6a74c9be805e042057b3b1", name: "test4", location: "test4", activityDate: "test4", description: "test4", …}
        4: {id: "5e6a74e4be805e042057b3b2", name: "test5", location: "test5", activityDate: "test5", description: "test5", …}
        length: 5
__proto__: Array(0)

MenuPage.js

const MenuPage = ({activities}) => {
    const [activity, setActivity] = useState([])

    console.log(activities)

    setActivity(activities.map( (activity) => <ActivityItem activity={activity} />))

App.js

const App = () => {
    const [activities, setActivities] = useState([])

    useEffect( () => {
        GQLClient({}).request(Query.getActivities, null).then( ({getActivities}) => {
            setActivities({getActivities})
        })
    }, [])

    const Load = (props, page) => {
        if (user.token === null) return <Redirect to="/login" />

        if (page === 'LogoutPage') {
            unsetUser()
            return <Redirect to="/login" />
        }

        switch (page) {
            case 'MenuPage': return <MenuPage activities={activities} />

            default:
        }
    }

    return (
        <BrowserRouter>
            <AppNavbar />
            <Switch>
                <Route exact path='/register' component={ RegisterPage } />
                <Route exact path='/login' component={ LoginPage } />
                <Route exact path='/' render={ (props) => Load(props, 'MenuPage') } />
            </Switch>
        </BrowserRouter>
  )
}
1
  • Why is MenuPage.js storing the activities in a state called activity? If you just want to render it then you return <>{activities.map(a=>ActivityItem activity={a} key={a.id}/>}</> Commented Mar 12, 2020 at 18:58

2 Answers 2

2

You are seeing the infinite renders as you are using setState is inside a component.

setActivity(activities.map( (activity) => <ActivityItem activity={activity} />))

When it encounters it it re renders the component, at which time it will run into the above state again on the next render.

Just remove it as you already have access to activities in the context of the component and just return from the component instead.

return activities.map( (activity) => <ActivityItem activity={activity} />)

naked useStates always causes infinite renders

Also it always makes sense to move the data source as close as possible as the App.js page does not really use it but rather passes it down to the child components.

You can move the useEffect to MenuPage after fixing the return statement and it should work as expected.

MenuPage.js

const MenuPage = ({activities}) => {
    const [activities, setActivities] = useState([])

    // This only causes a re render once when the component is mounted
    // as the dependency list is empty
    useEffect( () => {
        GQLClient({})
           .request(Query.getActivities, null)
           .then( ({getActivities}) => {
              setActivities({getActivities});
         })
    }, [])

    console.log(activities)

    return (
       activities.map( (activity) => <ActivityItem key={activity.id} activity={activity} />
    );
}
Sign up to request clarification or add additional context in comments.

4 Comments

Good anser, you forgot <ActivityItem activity={activity} key={activity.id}/> though
My bad. Updated it. Thanks !
Thank you so much! Do you know why whenever I add a new item, I need to refresh the MenuPage before the newly added item appears?
You are welcome. That is because you might not be updating activities with the new item that was added.
1

Unless some code is missing, MenuPage components cannot work. You have to return a React Node (ie: a JSX element), but you're not returning anything.

The errore you're getting is because you call setActivity() at every render, triggering a re-render every time (until React stops it with an error).

Comments

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.