Reactjs组件显示旧数据

时间:2017-05-03 14:22:58

标签: javascript reactjs react-redux

我有一个应该显示项目列表的组件。在首次加载组件时从API获取项目,然后在用户单击按钮时刷新/替换项目。

问题是,我的组件似乎总是落后于用户一步。例如,用户第一次单击按钮调用API并返回新数据,但组件仍显示初始加载时获得的数据。用户第二次单击时,我的组件会显示第一次单击时返回的数据。

我认为按钮点击后组件会快速重新加载,因此显示组件时状态不会更新,但我不知道如何解决它?

我的组件:

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {matchesFetchData} from '../actions/matches';
import Match from './match';


class MatchList extends Component {
    constructor(){
        super();
        this.generateNew = this.generateNew.bind(this);
    }  

    componentDidMount() {
        this.props.fetchData('http://localhost:4752/api/matches');
    }

    render() {
        if (this.props.hasErrored) {
            return <p>Sorry!There was an error loading the items</p>;
        }
        if (this.props.isLoading) {
            return <p>Loading…</p>;
        }

        return (   
            <div>
                <nav className="menu">
                    <input type="number" defaultValue="0" min="0" max="13" ref="safeguards"/>      
                    <button className="generateNew" onClick={this.generateNew}>Ny</button>         
                </nav>
                <ul className="matchlist">
                    {this.props.matches.map(function (match, index) {                        
                        return <Match key={index} match={match}/>
                    }) }
                </ul>
            </div>
        )
    }

    generateNew(e){
        e.preventDefault();
        const value = this.refs.safeguards.value;
        if(value == 0){
            this.props.fetchData('http://localhost:4752/api/matches');
        }
        else{
            this.props.fetchData('http://localhost:4752/api/matches/' + value);
        }
    }
}

const mapStateToProps = (state) => {
    return {
        matches: state.matchesApp.matches,
        hasErrored: state.matchesApp.matchesHasErrored,
        isLoading: state.matchesApp.matchesIsLoading
    };
};


const mapDispatchToProps = (dispatch) => {
    return {
        fetchData: (url) => dispatch(matchesFetchData(url))
    };
};  

export default connect(mapStateToProps, mapDispatchToProps)(MatchList);

操作:

export const MATCHES_HAS_ERRORED = 'MATCHES_HAS_ERRORED';
export const MATCHES_IS_LOADING = 'MATCHES_IS_LOADING';
export const MATCHES_FETCH_DATA_SUCCESS = 'MATCHES_FETCH_DATA_SUCCESS';

export function matchesHasErrored(bool){
    return {
        type: MATCHES_HAS_ERRORED,
        hasErrored: bool
    };
}

export function matchesIsLoading(bool){
    return {
        type: MATCHES_IS_LOADING,
        isLoading: bool
    };
}

export function matchesFetchDataSuccess(matches){
    return{
        type: MATCHES_FETCH_DATA_SUCCESS,
        matches
    };
}

export function matchesFetchData(url){
    return (dispatch) => {
        dispatch(matchesIsLoading(true));

        fetch(url)
        .then((response) => {
            if(!response.ok){
                throw Error(response.statusText);
            }

            dispatch(matchesIsLoading(false));

            return response;
        })
        .then((response) => response.json())
        .then((matches) => dispatch(matchesFetchDataSuccess(matches)))
        .catch(() => dispatch(matchesHasErrored(true)));
    }
}

减速机:

import {MATCHES_HAS_ERRORED, MATCHES_IS_LOADING, MATCHES_FETCH_DATA_SUCCESS} from '../actions/matches';

const initialState = {
    matchesIsLoading: false,
    matchesHasErrored: false,
    matches: []
}

export function matchesApp(state = initialState, action){
    switch(action.type){
      case MATCHES_HAS_ERRORED:
            return Object.assign({}, state, {
                matchesHasErrored: action.hasErrored
            });
      case MATCHES_IS_LOADING:
            return Object.assign({}, state, {
                matchesIsLoading: action.isLoading
            });
      case MATCHES_FETCH_DATA_SUCCESS:
            return Object.assign({}, state, {
                matchesIsLoading: false,
                matchesHasErrored: false,
                matches: action.matches
            });
      default:
            return state;
    }
}

匹配组件:

import React, {Component} from 'react';
import {Link} from 'react-router-dom';
import Result from './result';

class Match extends Component {
    constructor(props){
        super(props);
        this.match = this.props.match;
    }    

    render() {
        return (
            <li>
                <Link to={'/' + this.match.home + '/' + this.match.away}>
                    <span className="matchNumber">{this.match.number}</span>
                    <span className="matchup">
                        {this.match.home} - {this.match.away}
                    </span>
                    <Result value="1" selected={this.match.homeWin} odds={this.match.percent1}/><Result value="X" selected={this.match.draw} odds={this.match.percentX}/><Result value="2" selected={this.match.awayWin} odds={this.match.percent2}/>
                </Link>
            </li>
        )
    }
}

export default Match;

2 个答案:

答案 0 :(得分:4)

根据组件的外观,可能是您传递的键属性存在问题,如果显示值来自状态,组件将不会被完全删除,从而将显示陈旧数据

答案 1 :(得分:0)

你可以替换这个:

<ul className="matchlist">
  {this.props.matches.map(function (match, index) {                        
    return <Match key={index} match={match}/>
  }) }
</ul>

用这个:

let matchesData = this.props.matches.map(function (match, index) {                        
  return <Match key={index} match={match}/>
}) ;

...
return(
  <div>
    <nav className="menu">
      <input type="number" defaultValue="0" min="0" max="13" ref="safeguards"/>      
      <button className="generateNew" onClick={this.generateNew}>Ny</button>         
    </nav>
    <ul className="matchlist">
      {matchesData}
    </ul>
  </div>
)