简体   繁体   English

反应道具/状态未传递到模态窗口

[英]React props/state not passing to modal window

my first ever StackOverflow question, having been banging my head for about 4 hours! 我的第一个StackOverflow问题已经使我的头跳了大约4个小时!

I am building a react page that has an image gallery section. 我正在建立一个具有图像库部分的反应页面。 On the desktop site, when the user clicks on an image, it launches a Bootstrap modal pop up that should show the details of the clicked painting (title, size, type and media) and a larger image. 在桌面站点上,当用户单击图像时,它将启动Bootstrap模态弹出窗口,该弹出窗口应显示单击的绘画的详细信息(标题,大小,类型和媒体)和更大的图像。

I have got the modal working (without needing any special library like react-bootstrap) but whichever image is clicked, the modal only shows the image and details of the first image in the set. 我已经有了模态工作(不需要任何特殊的库,例如react-bootstrap),但是无论单击哪个图像,模态只显示图像和集合中第一个图像的细节。

I have tried all sorts of permutations of props and state, trying functional and class components, and nothing seems to work. 我已经尝试了道具和状态的各种排列,尝试了功能和类组件,但似乎没有任何效果。

Weirdly, if I look at each component in the chrome dev tools react DOM, the props for each image are set correctly, even in the class that renders the modal...but in the actual rendered page, it does not work. 奇怪的是,如果我看着chrome dev工具中的每个组件都对DOM做出反应,那么即使在渲染模式的类中,每个图像的props也都正确设置了……但是在实际的渲染页面中,它不起作用。

In my code, we have a Gallery component, containing many Holder components, each Holder contains a PortfolioItem, and the PortfolioItem contains a component called More that deals with the modal. 在我的代码中,我们有一个Gallery组件,其中包含许多Holder组件,每个Holder包含一个PortfolioItem,而PortfolioItem包含一个名为More的组件,用于处理模式。 As each Holder component defines props, these are passed down to each PortfolioItem (which works as I am getting the correct images and details in the gallery) and I just want those same props to show up in the modal. 当每个Holder组件定义道具时,它们会向下传递到每个PortfolioItem(当我在图库中获取正确的图像和详细信息时,它们会起作用),我只希望这些相同的道具显示在模式中。

import React from 'react';
import ReactDOM from 'react-dom';


class PortfolioItem extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        url: props.url,
        title: props.title,
        type: props.type,
        size: props.size,
        media: props.media
    };
}

render() {
    return (
        <div className="ot-portfolio-item">
            <More url={this.state.url} title={this.state.title} type={this.state.type} size={this.state.size}
                  media={this.state.media}/>
            <figure className="effect-border">
                <img src={this.state.url} className="img-responsive portfolio-img" alt={this.state.title}/>
                <figcaption>
                    <h2 className="paintingTitle">{this.state.title}</h2>
                    <p className="paintingDetail">{this.state.type}, {this.state.size}, {this.state.media}</p>
                    <a data-toggle="modal" data-target="#Modal"> </a>
                </figcaption>
            </figure>
        </div>
    );
}
}

class More extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        url: props.url,
        title: props.title,
        type: props.type,
        size: props.size,
        media: props.media
    };
}

render() {
    return (
        <div className="modal fade" id="Modal" aria-labelledby="Modal-label">
            <div className="modal-dialog">
                <div className="modal-content">
                    <div className="modal-header">
                        <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span
                            aria-hidden="true">&times;</span></button>
                        <h4 className="modal-title">{this.state.title}</h4>
                    </div>
                    <div className="modal-body">
                        <img src={this.state.url} alt={this.state.title} className="img-responsive"/>
                        <div className="modal-works">
                            <span>{this.state.type}</span>
                            <span>{this.state.size}</span>
                            <span>{this.state.media}</span>
                        </div>
                    </div>
                    <div className="modal-footer">
                        <button type="button" className="close btn btn-default" data-dismiss="modal"
                                aria-label="Close">Close
                        </button>
                    </div>
                </div>
            </div>
        </div>
    );
}
}


const Holder = (props) => {
return (
    <div className="col-sm-6 col-md-4 col-0-gutter holder">
        <PortfolioItem url={props.url} title={props.title} type={props.type} size={props.size} media={props.media}/>
    </div>
);
};

const Gallery = () => {
return (
    // When adding a new painting, just copy a <Holder/> in correct orientation section, and change the props!
    <div>
        {/* Landscape */}
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/girl.jpg" title="#Disengaged" type="Acrylic"
                size="24 by 16 inches" media="Board"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/swimming.jpg" title="Submerge" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/staithes.jpg" title="Staithes 2015" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/ladies.jpg" title="Nederlandes Meisjes" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/park.jpg" title="Family Stroll" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/mexican.jpg" title="Tree Of Life" type="Acrylic"
                size="12 by 10 inches" media="Canvas"/>

        {/* Square */}
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/face.jpg" title="Attitudes Of Colour" type="Acrylic"
                size="19.5 by 19.5 inches" media="Board"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/lee.jpg" title="Lee" type="Acrylic"
                size="19.5 by 19.5 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/boat.jpg" title="Drift Away" type="Acrylic"
                size="12 by 12 inches" media="Board"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/cindyself.jpg" title="Prizeworthy" type="Acrylic"
                size="19.5 by 19.5 inches" media="Canvas"/>

        {/* Portrait */}
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/diving.jpg" title="Ascent" type="Acrylic"
                size="32 by 40 inches" media="Ply"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/bluehair.jpg" title="Untitled" type="Acrylic"
                size="10 by 12 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/beach.jpg" title="Namaste" type="Acrylic"
                size="19.5 by 23.5 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/danielle.jpg" title="Concrete Jungle" type="Acrylic"
                size="19.5 by 23.5 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/africa.jpg" title="Untitled" type="Acrylic"
                size="19.5 by 23.5 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/sealady.jpg" title="Aqua Blue" type="Acrylic"
                size="32 by 40 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/violinman.jpg" title="Nightfall" type="Acrylic"
                size="11 by 14 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/indiangirl.jpg" title="Transition" type="Acrylic"
                size="19.5 by 23 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/indianboys.jpg" title="Backpacker's Tales" type="Acrylic"
                size="32 by 40 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront.net/indianwoman.jpg" title="Journey" type="Acrylic"
                size="19.5 by 23.5 inches" media="Board"/>
    </div>
);
};

const App = () => {
return (
    <Gallery/>
);
};

ReactDOM.render(<App/>, document.getElementById('root'));

Any pointers would be greatly appreciated! 任何指针将不胜感激!

Your issue is probably down to the fact that you are rendering the <More /> component and within the id of the modal is always the same. 您的问题可能归结为您正在渲染<More />组件,并且模态的id内始终相同。

So your line <a data-toggle="modal" data-target="#Modal"> </a> is going to always target id="Modal" . 因此,您的<a data-toggle="modal" data-target="#Modal"> </a>始终以id="Modal"为目标。 I suspect that your rendered html is actually invalid because your id's must be unique on a page. 我怀疑您呈现的html实际上是无效的,因为您的ID在页面上必须是唯一的。

If you change the ID of each modal rendered, then make sure the data-target links to the correct one, then it should work. 如果您更改了所呈现的每个模态的ID,请确保将data-target链接到正确的模态,然后它应该起作用。

Try to remove this kind of block code from each component, as you don't need : 尝试从每个组件中删除这种阻止代码,因为您不需要:

```js ```JS

constructor(props) {
    super(props);
    this.state = {
        url: props.url,
        title: props.title,
        type: props.type,
        size: props.size,
        media: props.media
    };
}

``` ```

By example : 例如:

render() {
let {url, title, size, type, media} = this.props;
    return (
        <div className="ot-portfolio-item">
            <More url={url} title={title} type={type} size={size}
                  media={media}/>
            <figure className="effect-border">
                <img src={url} className="img-responsive portfolio-img" alt={title}/>
                <figcaption>
                    <h2 className="paintingTitle">{title}</h2>
                    <p className="paintingDetail">{type}, {size}, {media}</p>
                    <a data-toggle="modal" data-target="#Modal"> </a>
                </figcaption>
            </figure>
        </div>
    );
}

use directly prop.url in your components. 在您的组件中直接使用prop.url And let's see. 让我们看看。

Cheers ! 干杯!

Modal must be rendred Just one Time ! 模态必须被贬低一次! and you pass data to that Modal onClick 然后您将数据传递给该模式onClick

class App extends React.Component {
 state = {
  data: {},
 }
sendData = (data) => {
 this.setState({ data });
}

render() {
 return (
  <div>
    <More data={this.state.data} />
    <Gallery sendData={this.sendData} />
  </div>
 );
 }
}

You are saving the component's props into its state - this is against a philosophy of React (maintaining a single source of truth) and will frequently cause bugs. 您正在将组件的props保存到其状态-这违反了React的哲学(保持单一事实来源),并且经常会导致bug。

A React component will re-render when either its props or its state changes, but the constructor will not be rerun. 当React组件的props或状态改变时,React组件将重新渲染,但是构造函数将不会重新运行。 Take this simplified component: 使用这个简化的组件:

class Simple extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: props.name
    }
  }

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

When we initially render <Simple name="Alex" /> then "Alex" is set to the state, the component renders and everything seems fine. 当我们最初渲染<Simple name="Alex" />然后将“ Alex”设置为状态,该组件将进行渲染,一切看起来都很好。 When this changes to <Simple name="Steve" /> then what happens? 如果将其更改为<Simple name="Steve" />那会发生什么? The props update, so the component re-renders. 道具会更新,因此组件会重新渲染。 Unfortunately, the component state has not changed, so the rendered output is the same. 不幸的是,组件状态没有改变,因此渲染的输出是相同的。

How do we fix this? 我们该如何解决? We maintain one source of truth. 我们维护真理的一种来源。 This means that any piece of information is stored in one, and only one, place in the application. 这意味着任何一条信息都存储在应用程序的一个位置中,并且只有一个位置。 In the case of the Simple component, this place is in the props. 对于简单组件,此位置在道具中。 We should refactor it to use the props in the render method: 我们应该重构它以在render方法中使用props:

class Simple extends React.Component {   
  render() {
     return (
       <div>{this.prop.name}</div>
     );
  }
}

Now that we've done that it doesn't even need to be a class any more: 现在我们已经完成了,它甚至不需要再成为一个类:

const Simple = ({ name }) => (
  <div>{name}</div>
);

You should do this refactoring now, because it will break your app either now or in the future. 您应该立即进行此重构,因为它立即或将来破坏您的应用程序。

Looking at your specific problem, the issue is most likely that you end up with multiple divs with the id "#Modal". 查看您的特定问题,该问题最有可能导致您以id为“ #Modal”的多个div结束。 Every More element you create creates a div with that id. 您创建的每个More元素都会创建一个具有该ID的div。 To distil your code down to a simpler form, let's use: 要将代码分解为更简单的形式,请使用:

const PortfolioItem = ({ name, url }) => (
  <div>
    <a data-toggle="modal" data-target="#Modal"> </a>
    <More name={name} url={url}
  </div>
);

const More = ({ name, url }) => (
  <div id="Modal">
    <a href={url}>{name}</a>
  </div>
);

What we really need is to have a unique id for each modal, so there is no confusion as to which one gets triggered. 我们真正需要的是每个模式都有唯一的ID,因此不会混淆哪个模式被触发。 We can do this simply by using the name prop as an id: 我们可以简单地通过使用名称prop作为id来做到这一点:

const PortfolioItem = ({ name, url }) => (
  <div>
    <a data-toggle="modal" data-target={name}> </a>
    <More name={name} url={url}
  </div>
);

const More = ({ name, url }) => (
  <div id={name}>
    <a href={url}>{name}</a>
  </div>
);

You may be able to find a more appropriate prop to use as the ID, or you could use a solution that uses array indices, or random characters. 您可能可以找到更适合用作ID的道具,或者可以使用使用数组索引或随机字符的解决方案。 The exact ids don't matter - they just need to be unique for each pair of PortfolioItem and More. 确切的ID无关紧要-对于每对PortfolioItem和更多项,它们仅需要唯一。

It is also worth noting that this is not an idiomatic way of handling modals in React. 还值得注意的是,这不是在React中处理模式的惯用方式。 Usually the open/closed state of the modal is stored within React itself, and handled using click handlers. 通常,模式的打开/关闭状态存储在React自身中,并使用点击处理程序进行处理。 If you want to go more down this path, then the react-modal library is an excellent path down which to go. 如果您想沿着这条路走得更远,那么react-modal库是一条理想的走之路。

when you use a tags,you dont have to use datta-toggle, use href instead (got it from bootstrap documentation) 使用标签时,不必使用datta-toggle,而应使用href(从引导文档中获取)

Note: For elements, omit data-target, and use href="#modalID" instead 注意:对于元素,请省略数据目标,而使用href =“#modalID”代替

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM