首页 文章

React模态在加载内容之间不会关闭

提问于
浏览
9

我正在使用这个react模式插件:https://github.com/reactjs/react-modal我需要在页面加载模式中显示一个对象数组 . 当第一项显示用户单击按钮时,isOpen prop对于Modal设置为false . 每个项目都有一个prop showModal,它将值提供给模态的isOpen . 当用户不断点击时,我会继续将当前对象上的值设置为false,然后将其设置为true以用于下一个对象 . 这一切都运行正常,但问题是叠加和对话窗口停留在屏幕上,只更新模态中的内容 . 我希望模态完全关闭并打开以显示数组中下一个对象的内容 . 我不得不将我的代码删除到下面的简化版本:

class ProductsModal extends React.Component {
  constructor(props) {
    super(props);
    this.remindMeHandler = this.remindMeHandler.bind(this);

    this.state = {
      products: [],
      modalId: 0
    };
  }

showModals() {
    let products = this.state.products;
    //A different function saves the array of product objects in the state so 
    //I can show them one by one

    let currentProduct = products[this.state.popUpId];

    if (products.length > 0) {
      return <ProductItemModal 
              product={currentProduct}
              showNextPopUp={() => this.showNextPopUp(currentProduct.productId)}
              showPopUp={currentProduct['showModal']}
              />;
    //showModal is a boolean for each product that sets the value of isOpen
    }
  }

  showNextPopUp() {
      //All this does is sets the "showModal" property to false for current 
     //product and sets it to true for next product so it shows in the Modal
  }


render() {
    return(
      <div>
        {this.showModals()}
      </div>
    );
  }
}

class ProductItemModal extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return(
      <Modal 
        isOpen={this.props.showModal}
        contentLabel="Product"
        id={this.props.product.productId}
        >
        <div>
         Product Data......
        </div>
      </Modal>
    );
  }
}

4 回答

  • 0

    为您的所有问题找到了解决方法并创建了这个codepen link . 就像这样,

    class ProductItemModal extends React.Component {
      render() {
        const { showModal, product, showNextModal, onClose } = this.props;
    
        return(
          <ReactModal 
            isOpen={showModal}
            contentLabel="Product"
            onRequestClose={() => onClose()}
            >
            <p>
              <b>Product Id</b> - {product.id}, <b>Product Name</b> - {product.name}
            </p>
            <button onClick={() => showNextModal()}>Next</button>
          </ReactModal>
        );
      }
    }
    
    class ProductsModal extends React.Component {
      constructor() {
        super();
    
        this.state = {
          products: [
            {id: 1, name: "Mac", showModal: true},
            {id: 2, name: "iPhone", showModal: false},
            {id: 3, name: "iPod", showModal: false},
          ],
          modalId: 0
        };
      }
    
      handleProductItemModalClose(product) {
        //backdrop click or escape click handling here
        console.log(`Modal closing from Product - ${product.name}`);
      }
    
      showModals() {
        const { products, modalId } = this.state;
        //A different function saves the array of product objects in the state so 
        //I can show them one by one
    
        let currentProduct = products[modalId];
    
        if(currentProduct) {
          return <ProductItemModal 
                  product={currentProduct}
                  showNextModal={() => this.showNextModal(currentProduct.id)}
                  showModal={currentProduct["showModal"]}
                  onClose={() => this.handleProductItemModalClose(currentProduct)}
                  />;
        //showModal is a boolean for each product that sets the value of isOpen
        }
      }
    
      showNextModal(currentProductId) {
        const { products, modalId } = this.state;
    
        var isLastModal = false;
        if(modalId === products.length - 1) {
          isLastModal = true;
        }
    
        var clonedProducts = [...products];
        var currentIndex = clonedProducts.findIndex(product => product.id === currentProductId);
        var newIndex = currentIndex + 1;
        clonedProducts[currentIndex].showModal = false;
        if(!isLastModal) {
          clonedProducts[newIndex].showModal = true;
        } else {
          //comment the following lines if you don't wanna show modal again from the start
          newIndex = 0;
          clonedProducts[0].showModal = true;
        }
          //All this does is sets the "showModal" property to false for current 
         //product and sets it to true for next product so it shows in the Modal
        this.setState({
          products: clonedProducts
        }, () => {
          this.setState({
            modalId: newIndex
          });
        });
      }
    
      render() {
        return(
          <div>
            {this.showModals()}
          </div>
        );
      }
    }
    
    ReactDOM.render(<ProductsModal />, document.getElementById("main"));
    

    如果有帮助,请告诉我 .

    Updated codepenhttps://codepen.io/anon/pen/rzVQrw?editors=0110

  • 4

    您需要调用ProductItemModal的setState()来关闭Model . 否则,虽然更改了isOpen,但不会重新呈现UI .

  • 1

    您可能知道react维护一个虚拟DOM,并且每次状态或props更改时,它会比较浏览器的DOM(实际dom)和虚拟DOM(React维护的DOM)之间的差异,以及每次更改isOpen属性时的代码你所做的只是改变模型组件的道具,这就是为什么React只更新实际模型的内部内容

    要完全关闭并重新打开模型,您需要对代码进行一些小改动

    而不是只返回 ProductsModal 中的一个模型组件,你需要做这样的事情,以便反应知道这个模态已经关闭而其他人已经打开 Key property is important 出于性能原因read more

    class ProductsModal extends React.Component {
     .
     .
     .
    
    showModals() {
        let products = this.state.products;
        //A different function saves the array of product objects in the state so 
    
    
        if (products.length > 0) {
          return (
            //return list of all modal component
            products.map((product) =>
               <ProductItemModal 
                  product={product}
                  showNextPopUp={() => this.showNextPopUp(product.productId)}
                  showPopUp={product['showModal']}
                  key={product.productId}
                  />
            )
          );
        //showModal is a boolean for each product that sets the value of isOpen
        }
      }
    
     .
     . 
     .
    }
    

    所有你在这里做的只是返回多个模态,当一个模型得到isOpen道具 false 是接近而另一个女巫得到 true 是开放现在反应知道有两个不同的模态因为 key props

  • 3

    另一种解决方法是使用 setTimeout . 实施如下 -

    class ProductItemModal extends React.Component {
      render() {
        const { showModal, product, selectNextProductFunc, onClose } = this.props;
    
        return(
          <ReactModal 
            isOpen={showModal}
            contentLabel="Product"
            onRequestClose={() => onClose()}
            >
            <p>
              <b>Product Id</b> - {product.id}, <b>Product Name</b> - {product.name}
            </p>
            <button onClick={() => selectNextProductFunc(product)}>Next</button>
          </ReactModal>
        );
      }
    }
    
    class ProductsModal extends React.Component {
      constructor() {
        super();
    
        this.state = {
          products: [
            {id: 1, name: "Mac"},
            {id: 2, name: "iPhone"},
            {id: 3, name: "iPod"},
          ],
          productId: null,
          showModal: true,
        };
      }
    
      handleProductItemModalClose(product) {
        //backdrop click or escape click handling here
        console.log(`Modal closing from Product - ${product.name}`);
      }
    
    
      showModals() {
        const { products, productId, showModal} = this.state;
        //A different function saves the array of product objects in the state so 
        //I can show them one by one
        const getProduct = function(){
          if(productId){
            return products.find((i) => i.id === productId);
          }else{
            return products[0]; // first element
          }
        }
    
    
          return <ProductItemModal 
                  product={getProduct()}
                  selectNextProductFunc={this.selectNextProductFunc.bind(this)}
                  showModal={showModal}
                  onClose={() => this.handleProductItemModalClose()}
                  />;
        //showModal is a boolean for each product that sets the value of isOpen
    
      }
    
      selectNextProductFunc(currentProduct) {
        const { products} = this.state;
        this.setState({
          showModal: false
        });
    
        const currentProductIndex = products.findIndex((i) => i.id === currentProduct.id);
        const modifiedIndex = 0;
        if(products[currentProductIndex + 1]){
          this.setState({
             productId : products[currentProductIndex + 1].id,
          });
        }else{
          this.setState({
             productId : modifiedIndex,
          });
        }
    
        setTimeout(() => {
            this.setState({
              showModal: true
            })
        }, 1000);
    
      }
    
      render() {
        return(
          <div>
            {this.showModals()}
          </div>
        );
      }
    }
    
    ReactDOM.render(<ProductsModal />, document.getElementById("main"));
    

    jsbin

相关问题