getDerivedStateFromProps не работает должным образом для React-Semanti c -UI - PullRequest
0 голосов
/ 08 января 2020

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

Однако я сталкиваюсь с проблемой, когда модал, который используется для обратной связи на странице профиля при загрузке изображения в качестве аватара, также запускается при выходе из панели меню / навигации.

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

        -------------
       | choose file |                       /* And this should trigger a Modal to confirm with a success OR failure!!
        -------------

Это мой модальный компонент:

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 { modalStateOn, 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})
 }

 static getDerivedStateFromProps(props, state) {
  if (props.isAlertModal !== state.isAlertModal) {
   return {
    isAlertModal: props.isAlertModal,
   };
  }
  // Return null if the state hasn't changed
  return null;
 }


 // componentDidUpdate(prevProps, prevState) {
 //  if (this.props.isAlertModal !== prevProps.isAlertModal) {
 //   this.setState({ isAlertModal: this.props.isAlertModal })
 //  }
 // }

 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.state.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)

Как вы можете видеть, я использую getDerivedStateFromProps и componentDidMount и задаю локальное состояние из избыточного состояния в качестве решения. .

Что также странно В компоненте Profile у меня есть пропеллер, используемый в качестве триггера для показа модального окна, который не имеет ничего общего с навигационным, но он все еще пузырится!

import React, { PureComponent } from 'react';
import './ImageUploader.css';
import ImageModal from '../Modal/MyModal.jsx'
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 PureComponent {
 constructor(props) {
  super(props);
    this.uploadImage = this.uploadImage.bind(this);
 }

 // componentDidUpdate(previousProps, previousState) {
 //  console.log("this.props.userAvatar in componentDidUpdate in ImageUploader", this.props.userAvatar)
 //  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

  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();
      console.log('this.props in ImageUploader uploadImageFunction', this.props)
     }
    })
    .catch((err) => {
     alert("Error while uploading image using multer");
      this.setDefaultImage();
    });
  }
 }

 render() {
  var {  userAvatar, modalActive } = 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>
    {(userAvatar) && <ImageModal
     key={userAvatar}
     isAlertModal={true}
     affirmativeUsed="OK!"
     message="Your image has been uploaded succesfully"
    />}
  </>
  );
 }
}

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

 return { userAvatar, modalActive }
}

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

export default connect(mapStateToProps, mapDispatchToProps)(ImageUploader)
...