React UseEffect Issue with GithubApi get contributors

127 Views Asked by At

Thanks to whoever can help me. I know it's a common thing to have the issue of useEffect re rendering. However in my case I have set it to render only once with the [] brackets but it keeps re rendering everything.

I'm calling my getRepoContributors() function in my RepoItem.js component

I'm working with the github api. I'm able to display users info and users repos. But when i try to get contributors for repos of a certain user it keeps re rendering.

Can't figure it out. Lost the whole day as Github API bans me because of multiple requests and need to wait for a about an hour every time before trying again.

UPDATE: DAY 2 Still can't make it work. Now trying to render from Repos.js component. But i get an error message. I commented out in RepoItem.js what I was trying first with the useeeffect that was not working.

"Cannot update a component (GithubState) while rendering a different component (Repos)."

Please help! Going nuts! Here are my updated files.


GithubState.js (context provider)


import React, { useReducer } from "react";
import axios from "axios";
import GithubContext from "./githubContext";
import GithubReducer from "./githubReducer";
import { 
  SEARCH_USERS, SET_LOADING, CLEAR_USERS, GET_USER, GET_REPOS, 
  GET_CONTRIBUTORS, FILTER_REPOS, CLEAR_FILTER_REPOS 
} from "../types";

let githubClientId;
let githubClientSecret;
.....
.....

const GithubState = (props) => {
  const initialState = {
    users: [],
    user: {},
    repos: [],
    contributors: [],
    loading: false,
    filteredRepos: null,
    error: null,
  };

  const [state, dispatch] = useReducer(GithubReducer, initialState);

  //Search Users
  const searchUsers = async (text) => {
    setLoading();

    const res = await axios.get(
      `https://api.github.com/search/users?q=${text}&client_id=${githubClientId}&client_secret=${githubClientSecret}`
    );

    //res.data.items is response from Github API
    dispatch({
      type: SEARCH_USERS,
      payload: res.data.items,
    });
  };

  //Clear Users
  const clearUsers = () => {
    dispatch({ type: CLEAR_USERS });
  };

  //Set Loading
  const setLoading = () => {
    dispatch({ type: SET_LOADING });
  };

  //Get 1 User
  const getUser = async (username) => {
    setLoading();

    const res = await axios.get(
      `https://api.github.com/users/${username}?client_id=${githubClientId}&client_secret=${githubClientSecret}`
    );
    console.log(`getUser     res.data`, res.data);

    dispatch({ type: GET_USER, payload: res.data });
  };

  //Get Repos
  const getUserRepos = async (username) => {
    setLoading();

    const res = await axios.get(
      `https://api.github.com/users/${username}/repos?sort=created:asc&client_id=
    ${githubClientId}&client_secret=
    ${githubClientSecret}`
    );

    console.log(`getUserRepos res.data`, res.data);

    dispatch({
      type: GET_REPOS,
      payload: res.data,
    });
  };

  // Get Repo Contributors
  const getRepoContributors = async (full_name) => {
    setLoading();

    const res = await axios.get(
      `https://api.github.com/repos/${full_name}/contributors?client_id=${githubClientId}&client_secret=${githubClientSecret}`
    );

    console.log(`getRepoContributors`, res.data);
    dispatch({
      type: GET_CONTRIBUTORS,
      payload: res.data,
    });
  };

  //Filter Repos
  const filterRepos = (text) => {
    dispatch({ type: FILTER_REPOS, payload: text });
  };

  //Clear Filter
  const clearFilterRepos = (text) => {
    dispatch({ type: CLEAR_FILTER_REPOS });
  };

  return (
    <GithubContext.Provider
      value={{
        users: state.users,
        user: state.user,
        loading: state.loading,
        repos: state.repos,
        contributors: state.contributors,
        filteredRepos: state.filteredRepos,
        error: state.error,
        searchUsers,
        clearUsers,
        getUser,
        getUserRepos,
        getRepoContributors,
        filterRepos,
        clearFilterRepos,
      }}
    >
      {props.children}
    </GithubContext.Provider>
  );
};

export default GithubState;

App.js


import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import GithubState from "./contexts/github/GithubState";
import Home from "./components/pages/Home";
import User from "./components/users/User";

import "./App.css";

const App = () => {
  return (
    <GithubState>
        <Router>
          <div className="App">
              <Switch>
                <Route exact path="/" component={Home} />
                <Route exact path="/user/:login" component={User} />
              </Switch>
          </div>
        </Router>
    </GithubState>
  );
};

export default App;

User.js

import React, { useContext, useEffect } from "react";
import Spinner from "../layout/Spinner";
import Repos from "../repos/Repos";
import ReposFilter from "../repos/ReposFilter";
import { Link } from "react-router-dom";
import GithubContext from "../../contexts/github/githubContext";

const User = ({ match, iconGithub }) => {
  const githubContext = useContext(GithubContext);

  const { getUser, loading, user, repos, getUserRepos, getRepoContributors
  } = githubContext;

  useEffect(() => {
    getUser(match.params.login);
    getUserRepos(match.params.login);
  }, []);

  const { name, avatar_url, location, public_repos } = user;

  if (loading) return <Spinner />;

  return (
    <div className="userpage-container">
     .........
     <div className="card grid-2">
        <div>
         .............
          <h1>{name}</h1>
          <p>Location : {location}</p>

          <div className="card text-center">
           ............
            <div className="badge">
              Public Repos: : {public_repos}
            </div>
          </div>
        </div>
        ............ 
      </div>

      <ReposFilter />
      <Repos repos={repos} />
    </div>
  );
};

export default User;

Repos.js


import React, { useContext, useEffect, useState } from "react";
import RepoItem from "./RepoItem";
import RepoItemPacha from "./RepoItemPacha";
import GithubContext from "../../contexts/github/githubContext";
import Spinner from "../layout/Spinner";

const Repos = () => {
  const githubContext = useContext(GithubContext);

  const [repoContributors, setRepoContributors] = useState();

  const {
    repos,
    filteredRepos,
    loading,
    contributors,
    getRepoContributors,
  } = githubContext;

  if (repos !== null && repos.length === 0 && !loading) {
    return <h4>No repos to show</h4>;
  }

  return (
    <div className="text-center">
      <>
        {repos !== null && !loading ? (
          <div>
            {filteredRepos !== null
              ? filteredRepos.map((repo) => (
                  <div key={repo.id} className="item">
                    <RepoItemPacha repo={repo} />
                  </div>
                ))
              : repos.map((repo) => (
                  <div key={repo.id} className="item">
                    {repo && getRepoContributors(repo.contributors_url)}
                    {contributors.map((contr) => (
                      <div key={contr.id} className="item">
                        <h3>{contr.login}</h3>
                      </div>
                    ))}
                    <RepoItemPacha repo={repo} />
                  </div>
                ))}
          </div>
        ) : (
          <Spinner />
        )}
      </>
    </div>
  );
};

export default Repos;

RepoItem.js

import React, { useEffect, useContext, useState } from "react";
import GithubContext from "../../contexts/github/githubContext";

const RepoItemPacha = ({ repo }) => {
  const githubContext = useContext(GithubContext);

  const [repoContributors, setRepoContributors] = useState();

  const { getRepoContributors, contributors, repos } = githubContext;

  // useEffect(() => {
  //   if (repo) {
  //     getRepoContributors(repo.contributors_url);
  //     console.log(
  //       `getRepoContributors(repo.contributors_url)`,
  //       getRepoContributors(repo.contributors_url)
  //     );
  //   }
  // }, [repo]);

  // useEffect(() => {
  //   if (contributors) {
  //     setRepoContributors(contributors);
  //   }
  // }, []);

  // let theContributors = [getRepoContributors(repo.full_name)];

  return (
    <div className="card">
      <h3>
        <a href={repo.html_url} target="_blank" rel="noopener noreferrer">
          {repo.name}
        </a>
      </h3>
      <h4>{repo.collaborators_url}</h4>

      {/* {repoContributors &&
        repoContributors.map((contr) => (
          <div key={contr.id} className="item">
            <h3>{contr.login}</h3>
          </div>
        ))} */}

      {repo.description && (
        <p>
          <strong>Description: </strong>
          {repo.description}
        </p>
      )}
      <p></p>
      {repo.language && (
        <p>
          <strong>Language: </strong>
          {repo.language}
        </p>
      )}
    </div>
  );
};

export default RepoItemPacha;

0

There are 0 best solutions below