9

我正在使用这个反应模式插件:https ://github.com/reactjs/react-modal 我需要在页面加载时在模式中显示一组对象。当第一项显示用户单击按钮时,模态的 isOpen 属性设置为 false。每个项目都有一个道具 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

4 回答 4

4

为您的所有问题找到了解决方法并创建了这个codepen 链接。会是这样的,

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"));

让我知道它是否有帮助。

更新代码笔:https : //codepen.io/anon/pen/rzVQrw ?editors=0110

于 2017-07-24T18:48:32.540 回答
3

您需要调用 ProductItemModal 的 setState() 来关闭模型。否则,尽管 isOpen 已更改,但 UI 不会重新呈现。

于 2017-07-24T07:20:37.353 回答
1

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

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

而不是只返回一个模型组件,ProductsModal你需要做这样的事情,以便反应知道这个模式已经关闭并且其他人已经打开关键属性对于性能原因很重要阅读更多

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是打开的,现在反应知道由于关键道具有两种不同的模态

于 2017-07-28T11:18:29.690 回答
0

另一种解决方法是使用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

于 2017-07-27T07:23:29.330 回答