0

有一个Login组件

// @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))
);

useEffect钩子中使用了pushfrom connected-react-router。钩子触发正常,但之后没有任何反应。

同样的方式,push是用在login行动中的。

// @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;

在这里,一切都成功并dispatch发生了,再也没有push发生过。

有什么问题?

4

2 回答 2

1

不应该dispatch(push('/dashboard'));吗?

于 2019-01-16T07:51:09.857 回答
0

您只需要确保在调用createRootReducer函数之前没有创建中间件并传入历史 API。

如果您尝试routerMiddleware(history)过早地创建中间件,历史将作为undefined. 按照README.md解释确切的执行顺序。

    // 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
}
于 2021-02-06T15:47:29.847 回答