[Redux] Fetching Data on Route Change

We will learn how to fire up an async request when the route changes.node

 

A mock server data:react

/** /api/index.js
 * Created by wanzhen on 7.6.2016.
 */
import { v4 } from 'node-uuid';

// This is a fake in-memory implementation of something
// that would be implemented by calling a REST server.

const fakeDatabase = {
    todos: [{
        id: v4(),
        text: 'hey',
        completed: true,
    }, {
        id: v4(),
        text: 'ho',
        completed: true,
    }, {
        id: v4(),
        text: 'let’s go',
        completed: false,
    }],
};

const delay = (ms) =>
    new Promise(resolve => setTimeout(resolve, ms));

export const fetchTodos = (filter) =>
    delay(500).then(() => {
        switch (filter) {
            case 'all':
                return fakeDatabase.todos;
            case 'active':
                return fakeDatabase.todos.filter(t => !t.completed);
            case 'completed':
                return fakeDatabase.todos.filter(t => t.completed);
            default:
                throw new Error(`Unknown filter: ${filter}`);
        }
    });

 

We want to replace localStorge with mock server data, so remove the localStorge code:redux

// configureStore.js

import { createStore } from 'redux';
import todoApp from './reducers';

const addLoggingToDispatch = (store) => {

    const rawDispatch = store.dispatch;

    // If browser not support console.group
    if (!console.group) {
        return rawDispatch;
    }

    return (action) => {
        console.group(action.type);
        console.log('%c prev state', 'color: gray', store.getState());
        console.log('%c action', 'color: blue', action);
        const returnValue = rawDispatch(action);
        console.log('%c next state', 'color: green', store.getState());
        console.groupEnd(action.type);
        return returnValue;
    };
};

const configureStore = () => {
    const store = createStore(todoApp);

    // If in production do not log it
    if (process.env.NODE_ENV !== 'production') {
        store.dispatch = addLoggingToDispatch(store);
    }

    return store;
};

export default configureStore;

 

We want to fetch data inside the component: VisibleTodoList.js.api

The good place to fetch data is in 'componentDidMount' lifecycle: This will fetch the initial data, which only run once.react-router

Thats not enough, we still need when the filter changes, it also need to fetch data, for that we can use another lifecycle 'componentDidUpdate'.async

import {connect} from 'react-redux';
import {toggleTodo} from '../actions';
import TodoList from './TodoList';
import {withRouter} from 'react-router';
import {getVisibleTodos} from '../reducers';
import  React, {Component}  from 'react';
import {fetchTodos} from '../api';


class VisibleTodoList extends Component {

    // Fetch data when component mount
    componentDidMount() {
        fetchTodos(this.props.filter)
            .then((todos) => {
                console.log(this.props.filter, todos);
            })
    }

    // Check the filter props, when it changes, fetch data again
    componentDidUpdate(prevProps) {
        if (this.props.filter !== prevProps.filter) {
            fetchTodos(this.props.filter)
                .then((todos) => {
                    console.log(this.props.filter, todos);
                })
        }
    }

    render() {
        return (
            <TodoList {...this.props}/>
        )
    }
}

const mapStateToProps = (state, {params}) => {
    const filter = params.filter || 'all';
    //todos, filter Will available in props
    return {
        todos: getVisibleTodos(state, filter),
        filter, 
    };
};

//re-assign the VisibleTodoList
VisibleTodoList = withRouter(connect(
    mapStateToProps,
    {onTodoClick: toggleTodo}
)(VisibleTodoList));

export default VisibleTodoList;
相關文章
相關標籤/搜索