Reputation: 11
I am working on a React portfolio composed of several pages, a home, profile, project list, and contact page. For this part of the portfolio, it is intended to display an array of my Github repositories.
I'm having issues interacting with the array -- it's behaving strangely, and I've been stuck on this for days. I can print the array in the state from the console, but when I try to do anything with it, it behaves as if it is empty.
For example (tests placed in render()):
console.log(this.state.repos); //Prints out array of repos, as expected
console.log(`Repos: ${this.state.repos)}`); //Prints string, no array
What's really vexing is that the expected results seem to appear on unmounting -- when I make a small edit to RepoTable or Repo and save the source file, when it reloads on localhost the table appears, and the list I expect to see logs on the console. When I hit refresh, everything disappears, and the table also displays blank when I deploy it to test on Heroku.
I've tried a few different methods to try to fix this, but I keep circling back to this same issue. Here are some of the things I tried:
I tried some other stuff, too, but I think the things I've tried are basically different ways of doing the same thing.
Here is the code for the RepoTable component:
class RepoTable extends Component {
constructor(props) {
super(props);
this.state = {
repos: this.get_repos()
}
}
get_repos(){
const repo_list = [];
axios
.get("https://api.github.com/users/Geno1131993/repos")
.then(function(response){
for(let i = 0; i < response.data.length; i++){
repo_list.push(response.data[i]);
}
});
return repo_list;
}
render() {
const repo_list = this.state.repos.map( (repo) => {
return (<Repo key = {repo.name} repo = {repo}></Repo>);
});
return (
<ul key="repo_table">
{repo_list}
</ul>
);
}
Here is the code for the Repo component (the random function assigns a random ID to the list item, and it gets assigned an icon in the CSS depending on what its name is determined to be):
class Repo extends Component {
constructor(props) {
super(props);
this.state = {
repo: props.repo
}
}
random(){
let key = Math.floor((Math.random() * 5) + 1);
switch(key){
case 1:
return "lotus1";
case 2:
return "lotus2";
case 3:
return "lotus3";
case 4:
return "lotus4";
case 5:
return "lotus5";
}
return -1;
}
render() {
return (
<li key = {this.state.repo.name} className="repo">
<a href={this.state.repo.html_url} rel="noreferrer" target="_blank">
<div className="repo_title">{this.state.repo.name}</div>
<div className="repo_info">
<p id={this.random()} className="lotus"></p>
<p className="repo_description">{this.state.repo.description}</p>
</div>
</a>
</li>
);
}
I don't receive any error messages, I just see an empty table -- thank you in advance for your thoughts and feedback!
Upvotes: 1
Views: 33
Reputation: 202686
The constructor is synchronous so it can't and won't wait for the data fetch made in get_repos
to resolve. Your initial repos
state is incorrect. You also can't make asynchronous calls to set initial state from within the constructor
, do this after the component mounts and actually save the response into state.
class RepoTable extends Component {
constructor(props) {
super(props);
this.state = {
repos: [] // <-- valid initial empty array
};
}
componentDidMount() {
this.get_repos(); // <-- fetch upon mounting
}
get_repos = async () => {
axios
.get("https://api.github.com/users/Geno1131993/repos")
.then(response => {
this.setState({
repos: response.data // <-- update state with response array
});
});
};
render() {
const repo_list = this.state.repos.map((repo) => {
return <Repo key={repo.name} repo={repo}></Repo>;
});
return <ul key="repo_table">{repo_list}</ul>;
}
}
Upvotes: 1