(React) 如何将模态内容与被点击的元素进行匹配?

(React) How to match the modal content with the clicked element?

我正在尝试将显示的模态与被点击的元素相匹配,现在我正在通过点击渲染所有模态,我一直试图使它们与索引相匹配但没有成功,请帮忙。

这是我的构造函数

constructor(props) {
    super(props);
    this.state = {
        portfolioData: [],
        newModal:[],
        modalPost: false,
        isShown: false
    };
} 

showModal = (i) =>{        
    this.setState({ isShown: true, modalPost: true })
} 

closeModal = () => {
    this.setState({isShown:false, modalPost: false})
}

在这里我获取数据并呈现两个列表组件和模态

componentDidMount() {
    axios.get(`data.json`)
        .then(res => {
            const portfolioData = [res.data.portfolio.projects.film];
            this.setState({ portfolioData });                  
        })
};

组件

const portfolioList = this.state.portfolioData.map((value) => 
    value.map((val, idx) =>             
        <PortfolioItem 
            id={val.title.en.toString().toLowerCase().split(" ").join("-")}
                title={val.title.en}
                imgsrc={val.imgsrc}
                status={val.status}
                profile={val.profile}
                director={val.director}
                production={val.production}
                showModal={this.showModal}
                youtube={val.trailer}
            />
))

const modalList = this.state.portfolioData.map((value) => 
    value.map((val, idx) =>             
        <Modal
            id={val.title.en.toString().toLowerCase().split(" ").join("-")}
            title={val.title.en}
            imgsrc={val.imgsrc}
            status={val.status}
            profile={val.profile}
            director={val.director}
            production={val.production}
            closeModal={this.closeModal}
            youtube={val.trailer}
        />                
    ))     

和 return

<section id="portfolio">                      
    { portfolioList }
    { this.state.modalPost !== false ? modalList : null }                
</section>

您的代码将创建与 this.state.portfolioData 保存的数据一样多的模态,这是不必要的、低效的并且可能导致渲染浪费。如果你退一步从这个角度思考,你将只渲染一个模态,但用所选项目的数据渲染它

让我们看一个例子,

我们可以从拥有一个额外的状态值 selectedValue 开始,它将保存被点击项目的值

this.state = {
  portfolioData: [],
  newModal:[],
  modalPost: false,
  isShown: false,
  selectedValue: {}  //<---
};

然后,当用户单击该项目时,我们可以在状态中设置该特定项目的值;具体在 selectedValue

const portfolioList = this.state.portfolioData.map((value) => 
    value.map((val, idx) =>             
        <PortfolioItem 
            id={val.title.en.toString().toLowerCase().split(" ").join("-")}
                title={val.title.en}
                imgsrc={val.imgsrc}
                status={val.status}
                profile={val.profile}
                director={val.director}
                production={val.production}
                showData={() => this.showData(val)}   //<---
                youtube={val.trailer}
            />
))

//new function for one specific task   <---
const showData = (value) => {
  this.setState({selectedValue: value}, this.showModal)
}

最后,您可以只渲染一个模态,而不是映射数据,它获取并显示来自 this.state.selectedValue

的数据
<Modal
 id={this.state.selectedValue.title.en.toString().toLowerCase().split(" ").join("-")}
 title={this.state.selectedValue.title.en}
 imgsrc={this.state.selectedValue.imgsrc}
 status={this.state.selectedValue.status}
 profile={this.state.selectedValue.profile}
 director={this.state.selectedValue.director}
 production={this.state.selectedValue.production}
 closeModal={this.closeModal}
 youtube={this.state.selectedValue.trailer}
/> 

这只是您可以遵循的想法。之后您应该 organize/optimize 根据您的代码库编写您的代码。如果您不熟悉 setState 的第二个参数,它会将回调作为第二个参数,在更新状态后执行。参考:https://reactjs.org/docs/react-component.html#setstate

希望这对你有帮助,干杯!

编辑:我刚刚注意到您没有在任何地方使用 isShown。这是模态应该根据的值打开。模式应该有一个道具,通过传递 true/false 使其成为 show/hide,检查文档。你应该将 this.state.isShown 传递给那个特定的 prop 来让所有东西一起工作!

问题是当您在 portfolioData 上循环时,您正在创建多个模态实例。我认为您不需要多个实例,因为您一次只会打开一个实例。

当您将模式状态设置为 isShown 时。您实际上是在生成的模态的所有实例上设置状态。因此,您最终会打开多个模式。理想情况下,您应该只有一个模态并将数据传递给模态。

你可以这样做:

首先,将模式移出循环,这样您就只有它的一个实例。

将数据传递给:

 <a>onClick={() => this.toggleModal(provider.data)} key={index}>Portfolio Item</a> 

最后,在toggleModal函数中先设置数据再打开模态

这样,您所有的 PortfolioItem 链接最终都会调用相同的模态实例。但是有不同的数据。设置数据后,您可以使用现有的 isShown 状态重新渲染组件。

这是一个小例子: 这样,您所有的 PortfolioItem 链接最终将调用相同的模态实例。但是有不同的数据。设置数据后,您可以使用已经存在的 isShown 状态重新渲染组件。

这是一个小例子:

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      isShown: false,
      data: ''
    }
    this.list = [{data: 'data1'}, {data: 'data2'}];
  }

  onAnchorClick({data},event){
    this.setState({data, isShown: true});
  }

  render(){
    return(
      <div>
        {this.list.map((obj, idx) => <div key={idx}>
          <a onClick={this.onAnchorClick.bind(this, obj)}>Portfolio Item</a>
        </div>)}

        <div style={{display: !this.state.isShown ? 'none' : 'block'}}>
          <h3>Data: {this.state.data}</h3>
        </div>
      </div>
    )
  }
}

window.onload = () => {
    ReactDOM.render(<App />, document.getElementById("app"));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>