javascript - React propsstate not passing to modal window - Stack Overflow

my first ever StackOverflow question, having been banging my head for about 4 hours!I am building a rea

my first ever StackOverflow question, having been banging my head for about 4 hours!

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.

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.

I have tried all sorts of permutations of props and state, trying functional and class ponents, and nothing seems to work.

Weirdly, if I look at each ponent 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.

In my code, we have a Gallery ponent, containing many Holder ponents, each Holder contains a PortfolioItem, and the PortfolioItem contains a ponent called More that deals with the modal. As each Holder ponent 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.

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=".jpg" title="#Disengaged" type="Acrylic"
                size="24 by 16 inches" media="Board"/>
        <Holder url=".jpg" title="Submerge" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url=".jpg" title="Staithes 2015" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url=".jpg" title="Nederlandes Meisjes" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url=".jpg" title="Family Stroll" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url=".jpg" title="Tree Of Life" type="Acrylic"
                size="12 by 10 inches" media="Canvas"/>

        {/* Square */}
        <Holder url=".jpg" title="Attitudes Of Colour" type="Acrylic"
                size="19.5 by 19.5 inches" media="Board"/>
        <Holder url=".jpg" title="Lee" type="Acrylic"
                size="19.5 by 19.5 inches" media="Canvas"/>
        <Holder url=".jpg" title="Drift Away" type="Acrylic"
                size="12 by 12 inches" media="Board"/>
        <Holder url=".jpg" title="Prizeworthy" type="Acrylic"
                size="19.5 by 19.5 inches" media="Canvas"/>

        {/* Portrait */}
        <Holder url=".jpg" title="Ascent" type="Acrylic"
                size="32 by 40 inches" media="Ply"/>
        <Holder url=".jpg" title="Untitled" type="Acrylic"
                size="10 by 12 inches" media="Canvas"/>
        <Holder url=".jpg" title="Namaste" type="Acrylic"
                size="19.5 by 23.5 inches" media="Canvas"/>
        <Holder url=".jpg" title="Concrete Jungle" type="Acrylic"
                size="19.5 by 23.5 inches" media="Canvas"/>
        <Holder url=".jpg" title="Untitled" type="Acrylic"
                size="19.5 by 23.5 inches" media="Canvas"/>
        <Holder url=".jpg" title="Aqua Blue" type="Acrylic"
                size="32 by 40 inches" media="Canvas"/>
        <Holder url=".jpg" title="Nightfall" type="Acrylic"
                size="11 by 14 inches" media="Canvas"/>
        <Holder url=".jpg" title="Transition" type="Acrylic"
                size="19.5 by 23 inches" media="Canvas"/>
        <Holder url=".jpg" title="Backpacker's Tales" type="Acrylic"
                size="32 by 40 inches" media="Canvas"/>
        <Holder url=".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!

my first ever StackOverflow question, having been banging my head for about 4 hours!

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.

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.

I have tried all sorts of permutations of props and state, trying functional and class ponents, and nothing seems to work.

Weirdly, if I look at each ponent 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.

In my code, we have a Gallery ponent, containing many Holder ponents, each Holder contains a PortfolioItem, and the PortfolioItem contains a ponent called More that deals with the modal. As each Holder ponent 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.

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/girl.jpg" title="#Disengaged" type="Acrylic"
                size="24 by 16 inches" media="Board"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront/swimming.jpg" title="Submerge" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront/staithes.jpg" title="Staithes 2015" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront/ladies.jpg" title="Nederlandes Meisjes" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront/park.jpg" title="Family Stroll" type="Acrylic"
                size="24 by 16 inches" media="Canvas"/>
        <Holder url="https://dgtqqzvj8521c.cloudfront/mexican.jpg" title="Tree Of Life" type="Acrylic"
                size="12 by 10 inches" media="Canvas"/>

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

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

Share Improve this question asked Mar 23, 2018 at 14:51 LeePNLeePN 231 silver badge4 bronze badges 2
  • No to answer your question, but a ment about your code. Rather than using ponent state within your Components, just use this.props. as you are not changing the state anywhere. – Tim B James Commented Mar 23, 2018 at 16:00
  • Thanks, yes I actually did that originally, I think the use of state was just something I tried whilst trying to solve the problem. – LeePN Commented Mar 23, 2018 at 16:31
Add a ment  | 

5 Answers 5

Reset to default 2

You are saving the ponent's props into its state - this is against a philosophy of React (maintaining a single source of truth) and will frequently cause bugs.

A React ponent will re-render when either its props or its state changes, but the constructor will not be rerun. Take this simplified ponent:

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 ponent renders and everything seems fine. When this changes to <Simple name="Steve" /> then what happens? The props update, so the ponent re-renders. Unfortunately, the ponent 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 ponent, this place is in the props. We should refactor it to use the props in the render method:

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". Every More element you create creates a div with that id. 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. We can do this simply by using the name prop as an 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. The exact ids don't matter - they just need to be unique for each pair of PortfolioItem and More.

It is also worth noting that this is not an idiomatic way of handling modals in React. Usually the open/closed state of the modal is stored within React itself, and handled using click handlers. If you want to go more down this path, then the react-modal library is an excellent path down which to go.

Your issue is probably down to the fact that you are rendering the <More /> ponent and within the id of the modal is always the same.

So your line <a data-toggle="modal" data-target="#Modal"> </a> is going to always target id="Modal". I suspect that your rendered html is actually invalid because your id's must be unique on a page.

If you change the ID of each modal rendered, then make sure the data-target links to the correct one, then it should work.

Try to remove this kind of block code from each ponent, as you don't need :

```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 ponents. And let's see.

Cheers !

Modal must be rendred Just one Time ! and you pass data to that Modal 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>
 );
 }
}

when you use a tags,you dont have to use datta-toggle, use href instead (got it from bootstrap documentation)

Note: For elements, omit data-target, and use href="#modalID" instead

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745160671a4614376.html

相关推荐

  • javascript - React propsstate not passing to modal window - Stack Overflow

    my first ever StackOverflow question, having been banging my head for about 4 hours!I am building a rea

    5小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信