我有一个应该显示项目列表的组件。在首次加载组件时从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;
答案 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>
)