首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用React Router 4实现React持久状态

使用React Router 4实现React持久状态
EN

Stack Overflow用户
提问于 2017-08-22 05:00:05
回答 1查看 2.8K关注 0票数 3

我的主页是从API获取数据,将其放入组件的状态,并基于此状态呈现元素。当我导航到一个子页面,然后我想再次转到主页时,会再次获取数据,这会导致不必要的加载。如何防止这种情况发生?如何确保当我单击指向主页或后退按钮的链接时,数据将立即加载?

代码语言:javascript
复制
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;

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-22 05:26:40

与其将你的状态保持在路由级别,不如让它保持在应用程序级别(或者像redux store一样,通过url更改/子项挂载/卸载而持久存在的某个地方)。

代码语言:javascript
复制
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文档中有一个关于“提升状态”的内容。使用React路由器时也适用同样的原则:https://facebook.github.io/react/docs/lifting-state-up.html

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45805436

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档