【问题标题】:Dispatch redux not executed调度 redux 未执行
【发布时间】:2019-09-10 09:42:26
【问题描述】:

我正在尝试在用户注册时提交表单。当点击提交按钮时,应该执行一个动作创建者来启动一个异步动作,但实际上提交并没有被触发,动作创建者也没有启动。

actions.ts:

import { ActionTypes } from "./types";
import { SignUpUser, User } from "../apis/authentication";
import { AxiosError } from "axios";
import { Dispatch } from "redux";

export interface ReturnedUser {
  username: string;
}
export interface SignUpSuccessAction {
  type: ActionTypes.SucceedSignUp;
  payload: ReturnedUser;
}

export interface SignUpFailAction {
  type: ActionTypes.FailSignUp;
  payload: string;
}

export interface SignUpStartAction {
  type: ActionTypes.StartSignUp;
}

const signUpStarted = (): SignUpStartAction => ({
  type: ActionTypes.StartSignUp
});

const signUpSucceeded = (user: ReturnedUser): SignUpSuccessAction => ({
  type: ActionTypes.SucceedSignUp,
  payload: user
});

const signUpFailed = (error: string): SignUpFailAction => ({
  type: ActionTypes.FailSignUp,
  payload: error
});

export const signUpFetch = (user: User) => {
  return async (dispatch: Dispatch) => {
    dispatch(signUpStarted());
    SignUpUser(user).then(
      (response: any) => {
        const { username } = response;
        return dispatch(signUpSucceeded(username));
      },
      (error: AxiosError) => {
        let errorMessage = "Internal Server Error";
        if (error.response) {
          errorMessage = error.response.data;
        }
        return dispatch(signUpFailed(errorMessage));
      }
    );
  };
};

reducers/reducer.ts:

import { Action, ActionTypes } from "../actions";

export const SignUpReducer = (state = {}, action: Action) => {
  switch (action.type) {
    case ActionTypes.SucceedSignUp:
      return { ...state, user: action.payload };

    case ActionTypes.FailSignUp:
      return { ...state, error: action.payload };

    default:
      return state;
  }
};

reducers/index.ts:

import { SignUpReducer } from "./signUp";
import { combineReducers } from "redux";

export const reducer = combineReducers({
  signUp: SignUpReducer
});

index.tsx:

import React from "react";
import ReactDOM from "react-dom";
import SignUp from "./containers/Signup/SignUp";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { reducer } from "./reducers/index";

const store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));

const App = () => <SignUp />;
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

SignUp.tsx:

import React, { useState } from "react";
import Button from "@material-ui/core/Button";
import { connect } from "react-redux";
import { Form, Field } from "react-final-form";
import { makeStyles, Theme, createStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import CardWrapper from "../../components/CardWrapper";
import PasswordField from "../../components/Password";
import TextField from "../../components/TextField";
import { validate, submit } from "./validation";

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    container: {
      padding: 16,
      margin: "auto",
      maxWidth: "100%",
      flexGrow: 1
    },
    paper: {
      padding: 16
    },
    item: {
      marginTop: 16
    }
  })
);

const SignUp = () => {
  const classes = useStyles();
  const [showPassword, setPassword] = useState(false);

  const handleClickShowPassword = () => {
    setPassword(!showPassword);
  };

  const handleMouseDownPassword = (
    event: React.MouseEvent<HTMLButtonElement>
  ) => {
    event.preventDefault();
  };
  return (
    <div className={classes.container}>
      <Form
        onSubmit={submit}
        validate={validate}
        render={({ handleSubmit, form, submitting, pristine }) => (
          <form onSubmit={handleSubmit}>
            <CardWrapper title='SignUp Form'>
              <Grid container justify='center' spacing={3}>
                <Grid item md={12}>
                  <Field fullWidth required name='username'>
                    {props => (
                      <TextField
                        label='Username'
                        type='text'
                        value={props.input.value}
                        onChange={props.input.onChange}
                        onBlur={props.input.onBlur}
                        meta={props.meta}
                        fullWidth={true}
                      />
                    )}
                  </Field>
                </Grid>
                <Grid item md={12}>
                  <Field fullWidth required name='email'>
                    {props => (
                      <TextField
                        label='Email'
                        type='email'
                        value={props.input.value}
                        onChange={props.input.onChange}
                        onBlur={props.input.onBlur}
                        meta={props.meta}
                        fullWidth={true}
                      />
                    )}
                  </Field>
                </Grid>
                <Grid item md={12}>
                  <Field fullWidth required name='password'>
                    {props => (
                      <PasswordField
                        value={props.input.value}
                        handleChange={props.input.onChange}
                        showPassword={showPassword}
                        handleClickShowPassword={handleClickShowPassword}
                        handleMouseDownPassword={handleMouseDownPassword}
                        fullWidth={true}
                        onBlur={props.input.onBlur}
                        meta={props.meta}
                      />
                    )}
                  </Field>
                </Grid>
                <Grid item className={classes.item}>
                  <Button
                    type='button'
                    variant='contained'
                    onClick={form.reset}
                    disabled={submitting || pristine}
                  >
                    Reset
                  </Button>
                </Grid>
                <Grid item className={classes.item}>
                  <Button
                    variant='contained'
                    color='primary'
                    type='submit'
                    disabled={submitting || pristine}
                  >
                    Submit
                  </Button>
                </Grid>
              </Grid>
            </CardWrapper>
          </form>
        )}
      />
    </div>
  );
};

export default connect()(SignUp);

validation.ts:

interface SignUpValues {
  email: string;
  password: string;
  username: string;
}

const submit = (values: SignUpValues) => {
  const user = {
    username: values.username,
    email: values.email,
    password: values.password
  };

  return signUpFetch(user);
};
export { submit };

我发现发布了关于Redux Dispatch Not Working in Action Creator 描述的同一问题的类似问题,但答案并不能解决我的问题。将不同的组件与 redux 链接时我会出错吗?

【问题讨论】:

  • 是的,您必须在连接函数中添加操作作为第二个参数 (mapDispatchToProps) 并从组件中调用该道具。请阅读docs

标签: reactjs typescript redux react-redux react-final-form


【解决方案1】:

它不会调度,因为在组件中你没有调度你的函数

return signUpFetch(user)

而是将组件与 Redux 连接并调度函数 在 Index.tsx 中

import { connect } from 'react-redux';

 const mapDispatchToProps = {
    submit
};

export default connect(null, mapDispatchToProps)(SignUp);

并使用

访问它

this.props.submit

在提交函数中添加调度

const submit = (values: SignUpValues) =>(dispatch, getState)=> {
  const user = {
    username: values.username,
    email: values.email,
    password: values.password
  };

  return dispatch(signUpFetch(user));
};

当您需要更新 redux 状态时,从它被调用的地方以及在操作中分派函数。

【讨论】:

  • 提交是一个函数而不是组件
  • 好的,然后在提交中分派并在调用提交的地方分派
  • 等我编辑我的答案你会明白的
  • 另一个也是?
  • 两者。这是我第一次将 react-final-form 与 typescript 一起使用,现在事情让我很困惑。
【解决方案2】:

您需要在进行调度时将组件连接到商店:

import { connect } from 'react-redux';

const submit = (values: SignUpValues) => {
  const user = {
    username: values.username,
    email: values.email,
    password: values.password
  };

  return this.props.signUpFetch(user);
};
export const connectedSubmit =  connect(null, {signUpFetch})(submit);
import { validate, connectedSubmit as submit } from "./validation";

您也可以返回SignUpUser


export const signUpFetch = (user: User) => {
  return async (dispatch: Dispatch) => {
    dispatch(signUpStarted());
    return SignUpUser(user).then(
      (response: any) => {
        const { username } = response;
        dispatch(signUpSucceeded(username));
      },
      (error: AxiosError) => {
        let errorMessage = "Internal Server Error";
        if (error.response) {
          errorMessage = error.response.data;
        }
        dispatch(signUpFailed(errorMessage));
      }
    );
  };
}

【讨论】:

    猜你喜欢
    • 2020-08-18
    • 2021-05-13
    • 2017-01-17
    • 2020-07-20
    • 2018-10-03
    • 2019-10-11
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多