Hayk Safaryan
Hayk Safaryan

Reputation: 2056

connected-react-router push is called nothing happens

There is a Login component

// @flow
import type {
  TState as TAuth,
} from '../redux';
import * as React from 'react';
import Button from '@material-ui/core/Button';
import FormControl from '@material-ui/core/FormControl';
import Input from '@material-ui/core/Input';
import InputLabel from '@material-ui/core/InputLabel';
import Paper from '@material-ui/core/Paper';
import { withNamespaces } from 'react-i18next';
import { Link } from 'react-router-dom';
import {
  connect,
} from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import useStyles from './styles';
import { login } from '../../redux';
import { push } from 'connected-react-router';
const logo = './assets/images/logo.png';

const {
  useEffect,
} = React;

type TInputProps = {
  input: Object,
  meta: {
    submitting: boolean,
  }
}
const UserNameInput = (props: TInputProps) => (
  <Input
    id="userName"
    name="userName"
    autoComplete="userName"
    autoFocus
    {...props}
    {...props.input}
    disabled={props.meta.submitting}
  />
);

const PasswordInput = (props: TInputProps) => (
  <Input
    name="password"
    type="password"
    id="password"
    autoComplete="current-password"
    {...props}
    {...props.input}
    disabled={props.meta.submitting}
  />
);

type TProps = {
  t: Function,
  login: Function,
  handleSubmit: Function,
  error: string,
  submitting: boolean,
  auth: TAuth,
}
// TODO: fix flow error inside
const Login = ({
  t,
  login,
  handleSubmit,
  error,
  submitting,
  auth,
}: TProps) => {
  const classes = useStyles();

  useEffect(() => {
    if (auth) {
      console.log('push', push);
      push('/dashboard');
    }
  }, [auth]);

  return (
    <main className={classes.main}>
      <Paper className={classes.paper}>
        <img src={logo} alt="logo" className={classes.logo} />
        <form
          className={classes.form}
          onSubmit={handleSubmit((values) => {
            // return here is very important
            // login returns a promise
            // so redux-form knows if it is in submission or finished
            // also important to return because
            // when throwing submissionErrors
            // redux-form can handle it correctly
            return login(values);
          })}
        >
          <FormControl margin="normal" required fullWidth>
            <Field
              name="userName"
              type="text"
              component={UserNameInput}
              label={
                <InputLabel htmlFor="userName">{t('Username')}</InputLabel>
              }
            />
          </FormControl>
          <FormControl margin="normal" required fullWidth>
            <Field
              name="password"
              type="password"
              component={PasswordInput}
              label={
                <InputLabel htmlFor="password">{t('Password')}</InputLabel>
              }
            />
          </FormControl>
          <div className={classes.error}>{error}</div>
          <Button
            disabled={submitting}
            type="submit"
            fullWidth
            variant="outlined"
            color="primary"
            className={classes.submit}
          >
            {t('Sign in')}
          </Button>
          <Link className={classes.forgot} to="/forgot">
            {t('Forgot Password?')}
          </Link>
        </form>
      </Paper>
    </main>
  );
};

const mapStateToProps = ({ auth }) => ({ auth });

const mapDispatchToProps = {
  login,
};

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(
  reduxForm({ form: 'login' })(withNamespaces()(Login))
);

In the useEffect hook the push from connected-react-router is used. The hook fires ok but nothing happens after it.

The same way, push is used in login action.

// @flow
import type {
  TReducer,
  THandlers,
  TAction,
  TThunkAction,
} from 'shared/utils/reduxHelpers';
import type {
  TUser,
} from 'shared/models/User';
import createReducer from 'shared/utils/reduxHelpers';
import urls from 'constants/urls';
import axios, { type $AxiosXHR } from 'axios';
import { SubmissionError } from 'redux-form';
import { push } from 'connected-react-router';

export type TState = ?{
  token: string,
  result: $ReadOnly<TUser>,
};

export const ON_LOGIN = 'ON_LOGIN';

export const login: ({ userName: string, password: string }) => TThunkAction =
  ({ userName, password }) => async (dispatch, getState) => {
    const res: $AxiosXHR<{username: string, password: string}, TState> =
      await axios.post(`${urls.url}/signin`, { username: userName, password })
        .catch((err) => {
          throw new SubmissionError({ _error: err.response.data.message });
        });
    const data: TState = res.data;

    dispatch({
      type: ON_LOGIN,
      payload: data,
    });
    push('/dashboard');
  };

const handlers: THandlers<TState, TAction<TState>> = {
  [ON_LOGIN]: (state, action) => action.payload,
};

const initialState = null;

const reducer: TReducer<TState> = createReducer(initialState, handlers);

export default reducer;

Here everything goes successful and dispatch happens and there is no push happening again.

Whats the problem?

Upvotes: 0

Views: 718

Answers (2)

Joe Gasewicz
Joe Gasewicz

Reputation: 1495

You just have to make sure that you do not create your middleware and pass in the history api before calling createRootReducer function.

If you try to create your middleware with routerMiddleware(history) too early , history will be passed in as undefined. Follow the README.md as it explains the exact execution order.

    // configureStore.js
...
import { createBrowserHistory } from 'history'
import { applyMiddleware, compose, createStore } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import createRootReducer from './reducers'
...
export const history = createBrowserHistory()

export default function configureStore(preloadedState) {
  const store = createStore(
    createRootReducer(history), // <-- Initiates the History API
    preloadedState,
    compose(
      applyMiddleware(
        routerMiddleware(history), // <--- Now history can be passed to middleware
        // ... other middlewares ...
      ),
    ),
  )

  return store
}

Upvotes: 0

Honza Pr&#225;šil
Honza Pr&#225;šil

Reputation: 70

Shouldn't there be dispatch(push('/dashboard')); ?

Upvotes: 2

Related Questions