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

标签 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;
}

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

谢谢。

最佳答案

以下行是问题所在:

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

通过定义此内联,这意味着 TransitionComponent 在每次重新渲染时都会看起来像一个新的组件类型,然后导致对话框的该部分重新安装,从而重做转换。

通过在组件函数外部将其定义为稳定的组件类型(我在下面将其称为 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

关于reactjs - 状态改变时对话框播放动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55296462/

相关文章:

javascript - 关闭请求在对话框中不起作用

javascript - 克隆 TypeScript 对象

javascript - 将 setState 作为参数传递 Typescript

javascript - 在 react-redux 演示组件中使用操作时遇到问题

javascript - 有条件地替换 redux reducer 中的状态值

javascript - JavaScript 中的意外标记

javascript - 似乎无法聚焦下一个 TextInput(React-Native)

javascript - 未捕获的语法错误 : Unexpected identifier - importing jquery

reactjs - 有条件保护路由(用户注册流程)

reactjs - 为什么使用 redux-persist 而不是手动将状态持久化到 localStorage?