Skip to content
This repository has been archived by the owner on Oct 26, 2018. It is now read-only.

How to Dispatch action on Enter #319

Closed
eMerzh opened this issue Mar 4, 2016 · 6 comments
Closed

How to Dispatch action on Enter #319

eMerzh opened this issue Mar 4, 2016 · 6 comments

Comments

@eMerzh
Copy link

eMerzh commented Mar 4, 2016

Hi,

thanks for this great lib...
i'm missing some doc about how to use your redux store to do some things with the locations.

like :

  • how to dispatch an action only , then redirect or something in a route (think of /logout )
  • how to make a route available only on given state....? i suppose it's through onEnter? but how to access the state then?
@timdorr
Copy link
Member

timdorr commented Mar 4, 2016

You can use a higher order function to get state into your onEnter hooks:

<Route path='/' component={App} onEnter={requireAuth(store)}>

And that hook might look something like:

function requireAuth(store) {
  return (nextState, replace) => {
    let { auth } = store.getState();

    if (!auth || !auth.loggedIn)
      replace({ pathname: loginPath, query: { return_to: nextState.location.pathname } });
  };
}

Or something to that effect.

@timdorr timdorr closed this as completed Mar 4, 2016
@welljs
Copy link

welljs commented Jun 16, 2016

This suggestion doesn't work with async actions

@timdorr
Copy link
Member

timdorr commented Jun 16, 2016

Yes, it does. You need to take in the 3rd argument to the hook function so you have a done callback. You can resolve any async stuff that way.

@welljs
Copy link

welljs commented Jun 16, 2016

Can you explain on example below, please?
That is my redux code:

const LOAD_WAITING = 'PROJECT@LOAD_WAITING';
const LOAD_SUCCESS = 'PROJECT@LOAD_SUCCESS';
const LOAD_FAIL = 'PROJECT@LOAD_FAIL';

const initialState = {
    waiting: false,
    data: {},
    fail: false 
};
export default function reducer (state = initialState, action = {}) {
    switch (action.type) {
        case LOAD_WAITING: 
            return {...state, waiting: true, error: false};
        break;
        case LOAD_SUCCESS: 
            return {...state, waiting: false, data: action.result, error: false};
        break;
        case LOAD_FAIL: 
            return {...state, waiting: false, error: true};
        break;
        default: 
            return state;
    }
}

//this is async action that handles by some middleware
function loadProject (id) {
    return {
        types: [LOAD_WAITING, LOAD_SUCCESS, LOAD_FAIL],
        promise: request => request(`/api/project/${id}`).get({})
    }
}

In usual way inside my container i @connect to the store and get all i need:

@connect(state => ({
    project: state.project
}))
export default class Project extends Component {
    //... component body
    render () {
        const {project} = this.props;
        //there the project data is accessibile, of course
        return (
            <div>
                Some markup
            </div>
        );
    }
}

But does it exist normal way to dispatch this async action inside onEnter?

import {loadProject} from './redux/project';

function load (store, dispatch) {
    return function (nextState, replace, next) {
        // how to dispatch(loadProject(nextState.params.id))
        // and execute next() in the end of this async operation?
    } 
}

export function getRoutes (store, dispatch) {
    return (
        <Router>
            <Route path="/" component={App}>
                <Route path="/project/:id/" component={Project} onEnter={load(store, dispatch)}/>
            </Route>
        </Router>
        );
}

@timdorr
Copy link
Member

timdorr commented Jun 16, 2016

You need some sort of middleware in your redux store that can take in a Promise and return it, so you can chain on a .then to call your next() in the onEnter hook.

I assume this is to preload your data, correct? I've found it's actually better to make that a static prop on your component that can do whatever actions will trigger the data to load. You can read that on the server side inside of your match and use a decorator/HoC on your client side to load it up in a React lifecycle event.

@welljs
Copy link

welljs commented Jun 16, 2016

Thanx for reply,
You right, I have middleware and it returns promise. When wrote the question insight visited me :) Function load will take this view:

function load (store, dispatch) {
    return function (nextState, replace, next) {
        dispatch(loadProject(nextState.params.id)).then(data => {
            //some code
            next();
        });
} 

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants