状态改变时对话框播放动画

时间:2019-03-22 09:24:20

标签: reactjs typescript redux material-ui

我正在使用Redux和material-ui

我正在尝试使用以下属性来运行带有<Slide direction="up"/>动画的Dialog:TransitionComponent

email是来自reducer的状态值,当我在TextField中输入值时会发生变化

当我尝试输入一些值时,动画会播放,但我只想播放一次。

enter image description here

    interface IProps extends WithStyles<typeof styles> {
      // ...
      setEmail: (email: string) => void;
      email: string;
      // ...
    }

    const LoginDialog: React.SFC<IProps> = props => {
      const handleClose = () => {
        props.setIsOpen(false);
      };

      const handlePasswordChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        props.setPassword(event.target.value);
      };

      const handlePasswordVisibility = () => {
        props.setPasswordVisibility(!props.passwordVisibility);
      };

      const handleEmailChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        props.setEmail(event.target.value);
      };

      return (
        <div>
          <Dialog
            open={props.isOpen}
            //dialog plays animation when props.isOpen changes
            TransitionComponent={props => <Slide direction="up" {...props} />}
            onClose={handleClose}
            aria-labelledby="login-dialog-slide-title"
            aria-describedby="login-dialog-slide-description"
            disableBackdropClick={true}
            keepMounted
          >
            <DialogTitle id="login-dialog-slide-title">
              <FormattedMessage id="logindialog_title" />
            </DialogTitle>
            <DialogContent>
              <TextField value={props.email} onChange={handleEmailChange} autoFocus type="email" label={<FormattedMessage id="logindialog_email" />}/>
              <TextField type="password" label={<FormattedMessage id="logindialog_password" />} />

            </DialogContent>
            <DialogActions>
              <Button onClick={handleClose} color="primary">
                <FormattedMessage id="logindialog_cancle" />
              </Button>
              <Button onClick={handleClose} color="primary">
                <FormattedMessage id="logindialog_ok" />
              </Button>
            </DialogActions>
          </Dialog>
        </div>
      );
    };

    export default withStyles(styles)(withRouter(LoginDialog));

我更新了具有mapStateToProps和操作,电子邮件的reducer的容器 而且您还可以在此处查看我的完整代码: codesandbox.io/s/nkrmw3wjxj

import { connect } from "react-redux";
import { ICombineReducersState } from "../../../reducers";
import LoginDialog from "./LoginDialog";
import {
  setIsOpen,
  setPassword,
  setPasswordVisibility,
  setEmail,
  setNickname,
  DuplicatedEmail,
  setIsEmailDuplicated
} from "../../../actions";

const mapStateToProps = (state: ICombineReducersState) => ({
  isOpen: state.open.isOpen,
  password: state.password.password,
  passwordVisibility: state.password.passwordVisibility,
  email: state.email.email,
  isPasswordError: state.password.isPasswordError,
  isEmailError: state.email.isEmailError,
  isEmailDuplicated: state.email.isEmailDuplicated
});

const mapDispatchToProps = (dispatch: any) => ({
  setIsOpen: (isOpen: boolean) => dispatch(setIsOpen(isOpen)),
  setPassword: (password: string) => dispatch(setPassword(password)),
  setPasswordVisibility: (passwordVisibility: boolean) =>
    dispatch(setPasswordVisibility(passwordVisibility)),
  setEmail: (email: string) => dispatch(setEmail(email)),
  setNickname: (nickname: string) => dispatch(setNickname(nickname)),
  DuplicatedEmail: () => dispatch(DuplicatedEmail()),
  setIsEmailDuplicated: (isEmailDuplicated: boolean) =>
    dispatch(setIsEmailDuplicated(isEmailDuplicated))
});

export const LoginDialogContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(LoginDialog);

export const SET_EMAIL = "SET_EMAIL";
export const SET_IS_EMAIL_DUPLICATED = "SET_IS_EMAIL_DUPLICATED";
import axios from "axios";
import config from "../config";

export interface IEmailAction {
    email: string;
    type: string;
    isEmailDuplicated: boolean;
}

export const setEmail = (email: string) => {
    return {
        email,
        type: SET_EMAIL,
    } as IEmailAction;
};

export const setIsEmailDuplicated = (isEmailDuplicated: boolean) => {
    return {
        isEmailDuplicated,
        type: SET_IS_EMAIL_DUPLICATED,
    } as IEmailAction;
}

export const DuplicatedEmail = () => (dispatch: any):boolean => {
    axios.get(`${config.REACT_APP_SERVER_URL}/users/email`)
    .then(res => {
        if (res.data.message.length >= 1) {
            return dispatch(setIsEmailDuplicated(true));
        }
    })
    .catch(err => {
        console.log(err.response)
    })

    return dispatch(setIsEmailDuplicated(false));
}

import { IEmailAction, SET_EMAIL, SET_IS_EMAIL_DUPLICATED } from "../actions";
export interface IEmailState {
    email: string;
    isEmailError: boolean;
    isEmailDuplicated: boolean;
}

const createEmpty = () => ({
    email: "",
    isEmailError: false,
    isEmailDuplicated: false,
});

const emailRegex = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;

export const emailReducer = (state = createEmpty(), action: IEmailAction) => {
    switch (action.type) {
        case SET_EMAIL: {
            return {
                email: action.email,
                isEmailError: !validateEmail(action.email),
                isEmailDuplicated: false,
            } as IEmailState;
        }
        case SET_IS_EMAIL_DUPLICATED: {
            return {
                email: state.email,
                isEmailError: true,
                isEmailDuplicated: action.isEmailDuplicated,
            } as IEmailState;
        }

        default:
            return state;
    }
};

const validateEmail = (email: string):boolean => {
    if (emailRegex.test(email)) {
        return true;
    }

    return false;
}

如果您需要更多信息,请告诉我。

谢谢。

1 个答案:

答案 0 :(得分:1)

以下一行是问题所在:

TransitionComponent={props => <Slide direction="up" {...props} />}

通过定义此内联语句,这意味着TransitionComponent将看起来像一个新的组件类型,每次重新渲染都将导致Dialog的该部分重新安装并因此重做过渡。

通过在组件函数外部将其定义为稳定的组件类型(以下将其称为TransitionComponent),然后将其用于TransitionComponent Dialog属性,可以轻松解决此问题:

const TransitionComponent = props => <Slide direction="up" {...props} />;

const LoginDialog: React.SFC<IProps> = props => {
...
  return (
    <div>
      <Dialog
        open={props.isOpen}
        TransitionComponent={TransitionComponent}
...
};

Edit relay-novel-client