Reactjs 响应缓存我的API请求

Reactjs 响应缓存我的API请求,reactjs,react-router,isomorphic-fetch-api,Reactjs,React Router,Isomorphic Fetch Api,我遇到了一个奇怪的问题,React似乎在更新课程后缓存我的API GET请求。最近刚开始学习,有很多新东西需要学习:) 过程: 首先,我转到courseList.js,它列出了所有课程。然后,我转到courseUpdate.js,它更新特定的课程并重定向回courseList.js 但是,更新课程后,我会被重定向回courseList.js,它会输出旧数据(在更新之前)。我检查了我的API服务器,发现我的React应用程序在补丁(更新)后没有发送任何请求。在我的控制台中,我还看到数据是过时的,但

我遇到了一个奇怪的问题,React似乎在更新课程后缓存我的API GET请求。最近刚开始学习,有很多新东西需要学习:)

过程:

首先,我转到courseList.js,它列出了所有课程。然后,我转到courseUpdate.js,它更新特定的课程并重定向回courseList.js

但是,更新课程后,我会被重定向回courseList.js,它会输出旧数据(在更新之前)。我检查了我的API服务器,发现我的React应用程序在补丁(更新)后没有发送任何请求。在我的控制台中,我还看到数据是过时的,但时间戳是当前的。此问题仅在我使用时发生

this.props.router.push('/courses');
or
browserHistory.push({pathname: '/courses'});
当我使用

window.location.href = '/courses';
js按预期加载新数据

如有任何帮助或见解,将不胜感激

谢谢

courseList.js文件:

constructor(props) {
    super(props);

    this.state = {
        courses: [],
        loading: true
    };

    console.log("Current token: "+sessionStorage.getItem('access_token'));
    console.log("Expires: "+sessionStorage.getItem('access_token_expires'));
}

componentDidMount() {
    fetchCourses()
        .then((data) => {
            this.setState(state => {
                console.log(new Date().toLocaleString());
                console.log(data);
                if(data["error"] === "invalid_grant"){
                    console.log("token expired...redirecting to login");
                    //TODO try to get new token without user redirect
                    this.props.router.push('/login');
                }else{
                    state.courses = data;
                    state.loading = false;
                    return state;
                }

            })
        })
        .catch((err) => {
            console.error('err', err);
        });
}

render() {
    let loading = this.state.loading ? 'loading' : 'loaded';
    return (
        <div>
            <h1>Course list</h1>

            <table className={"table table-hover table-responsive text-center " +loading}>
                <thead>
                <tr>
                    <th className="text-center">id</th>
                    <th className="text-center">Department</th>
                    <th className="text-center">Course Number</th>
                    <th className="text-center">Edit</th>
                </tr>
                </thead>
                <tbody>
                {this.state.courses && this.state.courses.map((post, i ) => {
                    return (
                        <tr key={post.id}>
                            <td>{post.id}</td>
                            <td>{post.department}</td>
                            <td>{post.course_number}</td>
                            <td>
                                <Link to={`/courses/${post.id}`} className="btn btn-default btn-sm">Edit</Link>
                                <btn onClick={this.deleteHandler.bind(this, post.id)} className="btn btn-danger btn-sm">Delete</btn>
                            </td>
                            <td>

                            </td>
                        </tr>
                    );
                })}

                </tbody>
            </table>
            <Link to={`/courses/create`} className="btn btn-default btn-sm">Create course</Link>
            <br/>
            <small>Page generated on: {new Date().toLocaleString()}</small>
        </div>
    );
}

乍一看,您似乎正在使用(组件)本地状态,而您应该使用应用程序状态

课程更新中的此.setState(…)
不会更新
课程列表中的相应课程。这与单页应用程序相关,尤其是在导航期间未卸载组件时(例如,我在上面的评论中提到的组件)

有两种方法可以做到这一点:

1-给一个共同的父母。这可能是解决这个问题最简单的方法。例如:

class ContainerComponent {
    updateItem = (item, newData) => {
        updateTheItem(item, newData).then((updatedItem) => {
            /* replace the item in state with updatedItem */
        });
    }

    componentDidMount() {
        fetchItems().then(/* store items in state */);
    }

    render() {
        const { items } = this.state;

        return (
            <div>
                <List items={ items } onItemSelect={(item) => this.setState({ selectedItem: item })}>
                <Detail item={ this.state.selectedItem } updateItem={ this.updateItem }>
            </div>
        )
    }
}
class集装箱组件{
updateItem=(项目,新数据)=>{
updateItem(item,newData)。然后((updateItem)=>{
/*将状态为的项替换为UpdateItem*/
});
}
componentDidMount(){
fetchItems()。然后(/*以状态*/)存储项;
}
render(){
const{items}=this.state;
返回(
this.setState({selectedItem:item})}>
)
}
}
在detail中,您可以调用
props.updateItem
,而不是更新那里的项目,这将在父级中更新它,并同步两个子级(都是
List
Details


2-我认为您正在寻找类似于
redux
(可能还有
react redux
绑定)的东西。状态将由单个存储管理,并且组件将一致地从中读取。如果它将是一个大型应用程序,我建议沿着这条路线走——如果没有帮助,管理许多不同组件之间的共享状态可能会变得棘手

CourseList
CourseUpdate
是否同时显示(即在主详细布局中?)如果是这样,当您导航到“远离”(react router链接不会在浏览器中引起导航事件)时,不会再次调用
componentDidMount
export function fetchCourses() {
    console.log("Fetching courses");
    return fetch(Config.apiBaseUrl+'/courses', {
        method: 'GET',
        mode: 'cors',
        headers: {
            'Accept': 'application/json',
            'Cache-Control': 'no-cache',
            'Authorization': 'Bearer '+auth.getToken(),
        },
        cache: 'no-cache'
    }).then(res => res.json())
        .catch(err => err);
}

export function updateCourse(id, data){
    return fetch(Config.apiBaseUrl+'/courses/'+id, {
        method: 'PATCH',
        mode: 'cors',
        body: JSON.stringify(data),
        headers: {
            'Accept': 'application/json',
            'Authorization': 'Bearer '+auth.getToken(),
            'Content-Type' : 'application/json'
        }
    }).then(res => {
        return res;
    }).catch(err => err);
}
class ContainerComponent {
    updateItem = (item, newData) => {
        updateTheItem(item, newData).then((updatedItem) => {
            /* replace the item in state with updatedItem */
        });
    }

    componentDidMount() {
        fetchItems().then(/* store items in state */);
    }

    render() {
        const { items } = this.state;

        return (
            <div>
                <List items={ items } onItemSelect={(item) => this.setState({ selectedItem: item })}>
                <Detail item={ this.state.selectedItem } updateItem={ this.updateItem }>
            </div>
        )
    }
}