Реакция: Неправильный модальный компонент вызывается после вызова ax ios - PullRequest
0 голосов
/ 06 января 2020

Я взял модальный компонент из response-semanti c -ui и настроил его на диалог подтверждения или предупреждения или на традиционный модал.

Я делал это в основном для того, чтобы попрактиковаться в создании более полезных и повторно используемых компонентов, а также косвенно, чтобы попрактиковаться в управлении и перемещении состояния для него в хранилище, т.е. в избыточность ...

import React, { Component } from 'react'
import { Button, Modal } from 'semantic-ui-react'
import PropTypes from 'prop-types'

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { logOutUser  } from '../../store/reducers/users/index'
import { modalStateOn, modalStateOff  } from '../../store/reducers/ui/index'


class MyModal extends Component {

 close = () => {
  const { modalStateOff } = this.props
  modalStateOff();
 }

 logOutUser = () => {
  const { logOutUser } = this.props
  logOutUser()
 }

 render() {
  const { modalActive } = this.props

   return (
    <>
      <Modal dimmer={'blurring'} centered={true} size={'mini'} open={modalActive} onClose={this.close}>
        <Modal.Header>
         <p>{this.props.message}</p>
        </Modal.Header>
        <Modal.Actions>
         {this.props.isAlertModal ?
         <Button
          color='black'
          onClick={this.close}
          content={this.props.affirmativeUsed}
         />
         :
        <>
         <Button
           color='black'
           onClick={this.close}
          >
           No
          </Button>
          <Button
           positive
           icon='checkmark'
           labelPosition='right'
           content={this.props.affirmativeUsed}
           onClick={() => { this.close(); this.logOutUser() }}
          />
        </>
         }
        </Modal.Actions>
      </Modal>
    </>
   )
 }
}

MyModal.propTypes = {
 message: PropTypes.string,
 affirmativeUsed: PropTypes.string
}

function mapStateToProps(state) {
 const { ui } = state
 const { modalActive } = ui

 return { modalActive }
}
const mapDispatchToProps = dispatch =>
 bindActionCreators({ logOutUser, modalStateOn, modalStateOff }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(MyModal)

Это работало фантастически для Модальный режим, который я хотел использовать для выхода из системы:

=======================================
home | profile | *dashboard | logout          /* You get a Modal to confirm your desire to log out */
=======================================

Однако на странице своего профиля я создал компонент ImageUploader, который обрабатывает загрузку изображений для этой страницы. Как вы уже могли догадаться, я хочу Модальное всплывающее окно также при успешном запросе axios и отказе дать какой-либо отзыв ...

=======================================
home | *profile | dashboard | logout          /* You get a Modal to confirm your desire to log out */
=======================================

        -------------
       | choose file |                       /* AND!!! Get a Modal to confirm with a success OR failure!!
        -------------

Это компонент ImageUploader:

import React, { Component } from 'react';
import './ImageUploader.css';
import FooModal from '../Modal/MyModal' 
import axios from 'axios';

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { loadAvatar } from '../../store/reducers/users/index'
import { modalStateOn, modalStateOff } from '../../store/reducers/ui/index'

class ImageUploader extends Component {
 constructor(props) {
  super(props);
    this.uploadImage = this.uploadImage.bind(this);
 }

 componentDidUpdate(previousProps, previousState) {
  if (previousProps.userAvatar !== this.props.userAvatar) {
  console.log("this.props.userAvatar in componentDidUpdate", this.props.userAvatar);
   loadAvatarImage(this.props.userAvatar)
  }
 }

 setDefaultImage(){
  var defaultImage =  '../../static/profile-avatars/assets/default-img.jpg';
  this.loadAvatarImage(defaultImage)
 }

 loadAvatarImage(img) {
  var { loadAvatar } = this.props;
  loadAvatar(img)
 }

 uploadImage(e, method) {

  const { modalStateOn } = this.props
  console.log('this.props in ImageUploader uploadImageFunction', this.props)

  if (method === "multer") {

   let imageFormObj = new FormData();

   imageFormObj.append("imageName", "multer-image-" + Date.now());
   imageFormObj.append("imageData", e.target.files[0]);

   this.loadAvatarImage(window.URL.createObjectURL(e.target.files[0]))

   var config = { headers: { 'content-type': 'multipart/form-data' }}
   axios.post(`http://localhost:8016/images/uploadmulter`, imageFormObj, config )
    .then((data) => {
     if (data.data.success) {
      console.log("data ", data);
      modalStateOn();
     return (
       <FooModal
       isAlertModal={true}
       open={true}
       affirmativeUsed="Yes"
       message="Your image has been uploaded succesfully"
      />
     )
     }
    })
    .catch((err) => {
     alert("Error while uploading image using multer");
      this.setDefaultImage();
    });
  }
    e.stopPropagation();

 }

 render() {
  var {  userAvatar } = this.props
  return (
   <>
    <div className="main-container">
     <h3 className="main-heading">Image Upload App</h3>

     <div className="image-container">
      <div className="process">
       <h4 className="process__heading">Process: Using Multer</h4>
       <p className="process__details">Upload image to a node server, connected to a MongoDB database, with the help of multer</p>
       <form action="/uploadmulter" method="post" encType="multipart/form-data" >
        <input type="file" name="avatar" className="process__upload-btn"
         onChange={(e) => {
          this.uploadImage(e, "multer");
        }} />
        <img src={userAvatar} alt="upload-image" className="process__image" />
       </form>
      </div>
     </div>
    </div>
  </>
  );
 }
}

function mapStateToProps(state) {
 const { ui, users } = state
 const { userAvatar } = users
 const { modalActive } = ui

 return { userAvatar, modalActive }
}

const mapDispatchToProps = dispatch =>
 bindActionCreators({ loadAvatar, modalStateOn }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(ImageUploader)

Интересно, что Modal для действия выхода из системы отображается вместо одного в ImageUploader ???

И

Когда я прохожу значение опоры для isAlertModal игнорируется?!

  <FooModal
   isAlertModal={true}
   open={true}
   affirmativeUsed="Yes"
   message="Your image has been uploaded succesfully"
  />

Итак, я полагаю, возможно, мне нужно отключить Modal в навигационной панели, чтобы позволить загрузчику изображений Modal распространяться?

* Имейте в виду, что функция uploadImage вызывает e.stopPropagation();, но не играет в кости!

Любая помощь будет принята!

ОБНОВЛЕНИЕ

Как предложил Eneias, рендеринг этого компонента (ImageModal) идет в функции рендеринга. Теперь это сработало, однако, что Модал выполняет рендеринг для функции выхода из системы.

Ответы [ 2 ]

3 голосов
/ 06 января 2020

Ваш FooModal должен быть включен в функцию рендеринга вместо функции обратного вызова.

Функция рендеринга вызывается каждый раз, когда меняется ваше состояние или реквизит. Итак, вы должны иметь флаг в вашем состоянии isUploaded или что-то в этом роде и использовать его в качестве условия для визуализации вашего FooModal.

В функции обратного вызова вашего метода post вы просто обновляете штат. Он снова запустит функцию рендеринга с новым состоянием.

0 голосов
/ 12 января 2020

Итак, я обнаружил, в чем проблема:

1. То, как я разбивал компонент Modal, было неверно !!!

 <Modal dimmer={'blurring'} centered={true} size={'mini'} open={modalActive} onClose={this.close}>
  <Modal.Header>
   <p>{this.props.message}</p>
  </Modal.Header>
    <Modal.Actions>
     {this.props.isAlertModal ?
      <Button
       color='black'
       onClick={this.close}
       content={this.props.affirmativeUsed}
      />
     :
     <>
      <Button
       color='black'
       onClick={this.close}
      >
       No
      </Button>
      <Button
       positive
       icon='checkmark'
       labelPosition='right'
       content={this.props.affirmativeUsed}
       onClick={() => { this.close(); this.logOutUser() }}
      />
     </>
    }
   </Modal.Actions>
 </Modal>

Был только один <Model.Header>, this.props.message и <Modal.Actions>, обслуживающий два выхода. троичный:

Это должно быть записано так:

    <>
     <Modal dimmer={'blurring'} centered={true} size={'mini'} open={open} onClose={this.close}>
      {avatarModalActive === true ?
       <>
        <Modal.Header>
         <p>{this.props.message}</p>
        </Modal.Header>
         <Modal.Actions>
         <Button
          color='black'
          onClick={()=> {this.close()}}
          content={this.props.affirmativeUsed}
         />
         </Modal.Actions>
       </>
         :
        <>
        <Modal.Header>
         <p>{this.props.message}</p>
        </Modal.Header>
        <Modal.Actions>
         <Button
          color='black'
          onClick={this.close}
         >
           No
         </Button>
         <Button
          positive
          icon='checkmark'
          labelPosition='right'
          content={this.props.affirmativeUsed}
          onClick={() => {this.close(); this.logOutUser()}}
         />
         </Modal.Actions>
        </>
         }
      </Modal>
    </>

 And I would up realizing I had one piece of `state` serving both Modals.

    const { avatarModalActive, modalActive } = this.props /* Now there are two pieces of state managing each modal */
      var open;

      if (avatarModalActive) open = avatarModalActive 
      else open = modalActive 

This is the complete Modal File:

import React, { PureComponent, Component } from 'react'
import { Button, Modal } from 'semantic-ui-react'
import PropTypes from 'prop-types'

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { logOutUser  } from '../../store/reducers/users/index'
import { avatarModalStateOff, modalStateOff  } from '../../store/reducers/ui/index'


class MyModal extends PureComponent {
 constructor(props) {
  super(props);
  this.state = {
   isAlertModal: this.props.isAlertModal
  }
 }

 componentDidMount() {
  const { isAlertModal } = this.props;
  this.setState({ isAlertModal: isAlertModal})
 }

 close = () => {
  if (this.props.avatarModalActive){
   this.props.avatarModalStateOff();
  }
  this.props.modalStateOff();
 }

 logOutUser = () => {
  const { logOutUser } = this.props
  logOutUser()
 }

 render() {
  const { avatarModalActive, modalActive } = this.props
  var open;

  if (avatarModalActive) open = avatarModalActive
  else open = modalActive

   return (
    <>
     <Modal dimmer={'blurring'} centered={true} size={'mini'} open={open} onClose={this.close}>
      {avatarModalActive === true ?
       <>
        <Modal.Header>
         <p>{this.props.message}</p>
        </Modal.Header>
         <Modal.Actions>
         <Button
          color='black'
          onClick={()=> {this.close()}}
          content={this.props.affirmativeUsed}
         />
         </Modal.Actions>
       </>
         :
        <>
        <Modal.Header>
         <p>{this.props.message}</p>
        </Modal.Header>
        <Modal.Actions>
         <Button
          color='black'
          onClick={this.close}
         >
           No
         </Button>
         <Button
          positive
          icon='checkmark'
          labelPosition='right'
          content={this.props.affirmativeUsed}
          onClick={() => {this.close(); this.logOutUser()}}
         />
         </Modal.Actions>
        </>
         }
      </Modal>
    </>
   )
 }
}

MyModal.propTypes = {
 message: PropTypes.string,
 affirmativeUsed: PropTypes.string
}

function mapStateToProps(state) {
 const { ui } = state
 const { modalActive, avatarModalActive } = ui

 return { modalActive, avatarModalActive }
}
const mapDispatchToProps = dispatch =>
 bindActionCreators({ logOutUser, avatarModalStateOff, modalStateOff }, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(MyModal)

И это файл Redux:

`ui.js`

/* initial state */
export var uiStartState = { modalActive: false, avatarModalActive: false, }

/* action types */
export const actionTypes = {
    MODAL_ACTIVE: 'MODAL_ACTIVE',
    MODAL_INACTIVE: 'MODAL_INACTIVE',
    AVATAR_MODAL_ACTIVE: 'AVATAR_MODAL_ACTIVE',
    AVATAR_MODAL_INACTIVE: 'AVATAR_MODAL_INACTIVE',
}

/* reducer(s) */
export default function ui(state = uiStartState, action) {
    switch (action.type) {

        case actionTypes.MODAL_ACTIVE:
            return Object.assign({}, state, { modalActive: true });

        case actionTypes.MODAL_INACTIVE:
            return Object.assign({}, state, { modalActive: false });

        case actionTypes.AVATAR_MODAL_ACTIVE:
            return Object.assign({}, state, { avatarModalActive: true });

        case actionTypes.AVATAR_MODAL_INACTIVE:
            return Object.assign({}, state, { avatarModalActive: false });

        default:
            return state
    }
};

/* actions */
export const modalStateOn = () => {
    return { type: actionTypes.MODAL_ACTIVE }
}

export const modalStateOff = () => {
    return { type: actionTypes.MODAL_INACTIVE }
}

export const avatarModalStateOn = () => {
    return { type: actionTypes.AVATAR_MODAL_ACTIVE }
}

export const avatarModalStateOff = () => {
    return { type: actionTypes.AVATAR_MODAL_INACTIVE }
}

Надеюсь, это имеет смысл!

...