使用React Router 4

时间:2017-08-21 21:00:05

标签: javascript reactjs react-router frontend react-router-v4

我的主页是从API获取数据,将其放入组件的状态并根据此状态呈现元素。 当我导航到子页面然后我想再次访问主页时,再次获取数据会导致不必要的负载。怎么预防?如何确保当我点击主页或后退按钮的链接时,数据会立即加载?

import React, {Component} from 'react';
import axios from 'axios';
import _ from 'lodash';
import { Link } from 'react-router-dom';

import ContributorsTable from './ContributorsTable';
import LoadingScreen from './LoadingScreen';

export const API_KEY = 'api-key'
const org = `https://api.github.com/orgs/angular?${API_KEY}`;
const unorderedContributors = [];
let contributorsList = [];
const contributorPromises = [];
const contributorPropertiesPromises = [];

class GitHubLists extends Component {
    constructor(props) {
        super(props);

        this.state = {
            repos: [],
            contributors: [],
            isLoaded: false
        };
    }
    componentDidMount() {
        axios.get(org)
        .then(res => {
            let numberRepos = res.data.public_repos;
            let pages = Math.ceil(numberRepos/100);
            let tmpRepos = [...this.state.repos];
            for(let page = 1; page <= pages; page++) {
                axios.get(`https://api.github.com/orgs/angular/repos?page=${page}&per_page=100&${API_KEY}`)
                .then(res => {
                    for(let i = 0; i < res.data.length; i++) {
                        tmpRepos.push(res.data[i]);
                    }
                    this.setState({repos: tmpRepos});
                })
                .then(() => {
                    this.state.repos.map(repo =>
                        contributorPromises.push(axios.get(`${repo.contributors_url}?per_page=100&${API_KEY}`)
                        .then(res => {
                            if(!res.headers.link) {
                                unorderedContributors.push(res.data);
                            }
                      
                            else {
                                for(let page = 1; page <= 5; page++) {//5 pages because of github limitation - can be done by recursion checking if res.headers.link.includes('rel="next"')
                                  contributorPromises.push(
                                    axios.get(`${repo.contributors_url}?page=${page}&per_page=100&${API_KEY}`)
                                    .then(res => unorderedContributors.push(res.data))
                                  )
                                }
                            }
                        }))
                    );
                      
                    Promise.all(contributorPromises).then(() => {
                    
                    contributorsList = _.chain(unorderedContributors)
                    .flattenDeep()
                    .groupBy('id')
                    .map((group, id) => ({
                        id: parseInt(id, 10),
                        login: _.first(group).login,
                        contributions: _.sumBy(group, 'contributions'),
                        contributorFollowers: 0,
                        followers_url: _.first(group).followers_url,
                        contributorRepositories: 0,
                        repos_url: _.first(group).repos_url,
                        contributorGists: 0,
                        gists_url: _.first(group).gists_url,
                        avatar: _.first(group).avatar_url,
                        url: _.first(group).html_url
                    }))
                    .orderBy(['contributions'],['desc'])
                    .filter((item) => !isNaN(item.id))
                    .value();
                    
                    this.setState({contributors: contributorsList})
                    })
                    .then(() => {
                        let tmpContributors = [...this.state.contributors];
                        tmpContributors.map(contributor => contributor.gists_url = (contributor.gists_url).slice(0, -10));
                        tmpContributors.map(contributor => {
                            return contributor.link =
                            <div>
                                <Link 
                                    to={{
                                        pathname: `contributors/${contributor.login}`,
                                        state: {
                                            login: contributor.login,
                                            id: contributor.id,
                                            repos_url: contributor.repos_url,
                                            avatar: contributor.avatar
                                        }
                                    }}
                                >
                                See profile
                                </Link>
                            </div>
                        });
                        const getContributorProperties = (propertyUrl, contributorProperty) => {
                            for (let i = 0; i < 10; i++) {
                                contributorPropertiesPromises.push(axios.get(`${tmpContributors[i][propertyUrl]}?per_page=100&${API_KEY}`)
                                    .then(res => {
                                        if(res.data.length > 100) {
                                            tmpContributors[i][contributorProperty] = res.data.length;
                                        } 
                                        else {
                                            for(let page = 1; page <= 5; page++) {
                                                axios.get(`${tmpContributors[i][propertyUrl]}?page=${page}&per_page=100&${API_KEY}`)
                                                tmpContributors[i][contributorProperty] += res.data.length;
                                            }
                                        }
                                    })
                                )
                            }
                        }
                        getContributorProperties('followers_url', 'contributorFollowers');
                        getContributorProperties('repos_url', 'contributorRepositories');
                        getContributorProperties('gists_url', 'contributorGists');
                        Promise.all(contributorPropertiesPromises)
                        .then(() => this.setState({contributors: tmpContributors, isLoaded: true}))
                        
                    })
                })
            }
        })          
    }
    render() {
        if(this.state.isLoaded) {
                return <ContributorsTable data={this.state.contributors}/>;
        }
        else {
            return <LoadingScreen />
        }
    }
}

export default GitHubLists;

1 个答案:

答案 0 :(得分:1)

不要将您的状态保持在路由级别,而是将其保持在应用级别(或者在网址更改/子项安装+卸载的地方,如redux存储区)。

class App {
  state = { data: null }
  fetchData() {
    callApi().then(data => this.setState({ data }))
  }
  render() {
    return (
      <Router>
        <div>
          <Route 
            path="/page" 
            component={props => 
              <Page data={this.state.data} fetchData={this.fetchData} />
            }
          />
        </div>
      </Router>
    )
  }
}

class Page {
  componentDidMount() {
    if (!this.props.data) this.props.fetchData()
  }
  render() { ... }
}

React docs在&#34;解除状态&#34;上有一个位置。使用React Router时,同样的原则适用:https://facebook.github.io/react/docs/lifting-state-up.html