user9617046
user9617046

Reputation:

React bootstrap modal not rendering updated data

When I'm running the below code and clicking the "Read" button, data is not updating in modal window even though I have few different components rendered.

I'm new to react, I have read similar posts that it has something to do with changing state but don't really know how to apply it in this case?

import React, { Component } from "react";
import Moment from "react-moment";
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
import ButtonToolbar from "react-bootstrap/ButtonToolbar";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import Container from "react-bootstrap/Container";
import CardDeck from "react-bootstrap/CardDeck";
import Modal from "react-bootstrap/Modal";
import "./posts.css";

const config = require("../../config").config();
class MyVerticallyCenteredModal extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Modal
        {...this.props}
        size="lg"
        aria-labelledby="contained-modal-title-vcenter"
        centered
      >
        <Modal.Header closeButton>
          <Modal.Title id="contained-modal-title-vcenter">
            {this.props.title}
          </Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <pre>{this.props.title}</pre>
        </Modal.Body>
        <Modal.Footer>
          <Button onClick={this.props.onHide}>Close</Button>
        </Modal.Footer>
      </Modal>
    );
  }
}

This is my parent component where I'm having button opening modal, post.title and post.body is not being updated on modal.

  class Posts extends Component {
      constructor() {
        super();
        this.state = {
          posts: [],
          modalShow: false
        };
      }
      componentDidMount() {
        fetch(config.localhostPrefix + "/api/stories")
          .then(res => res.json())
          .then(posts => this.setState({ posts }));
      }
      render() {
        let modalClose = () => this.setState({ modalShow: false });
        return (
          <div className="Posts">
            <h2>Posts</h2>
            <CardDeck>
              {this.state.posts.map(post => (
                <Card key={post._id}>
                  <Card.Body>
                    <Card.Title>"{post.title}"</Card.Title>
                    <Card.Text>
                      {post.body}
                      <ButtonToolbar>
                        <Button
                          variant="primary"
                          onClick={() => this.setState({ modalShow: true })}
                        >
                          Read
                        </Button>
                        <MyVerticallyCenteredModal
                          show={this.state.modalShow}
                          title={post.title}
                          body={post.body}
                          onHide={modalClose}
                        />
                      </ButtonToolbar>
                    </Card.Text>
                  </Card.Body>
                  <Card.Footer>
                    <Container>
                      <Row>
                        <Col>
                          <small className="text-muted">
                            Created:
                            <Moment format=" YYYY/MM/DD hh:mm">
                              {post.createdAt}
                            </Moment>{" "}
                          </small>
                        </Col>
                      </Row>
                      <Row>
                        <Col>
                          <small className="text-muted">
                            Updated:
                            <Moment format=" YYYY/MM/DD hh:mm">
                              {post.updatedAt}
                            </Moment>
                          </small>
                        </Col>
                      </Row>
                      <Row>
                        <Col>
                          <small className="text-muted">
                            Author: {post.author}{" "}
                          </small>
                        </Col>
                      </Row>
                    </Container>
                  </Card.Footer>
                </Card>
              ))}
            </CardDeck>
          </div>
        );
      }
    }
    export default Posts;

Upvotes: 1

Views: 2600

Answers (1)

codejockie
codejockie

Reputation: 10862

Thanks for creating the sandbox. I was able to fix the issue you're having. I slightly modified your Posts component. You were close but had one or two things you missed out. Please see my changes below:

class Posts extends Component {
  constructor() {
    super();
    this.state = {
      posts: [
        { _id: 1, title: "title1", body: "body1", author: "author1" },
        { _id: 2, title: "title2", body: "body2", author: "author2" },
        { _id: 3, title: "title3", body: "body3", author: "author3" }
      ],
      postId: null,
      modalShow: false
    };
  }
  modalClose = id => {
    this.setState({ modalShow: !this.state.modalShow, postId: id });
  };
  renderModal = () => {
    const { modalShow, postId, posts } = this.state;
    const post = posts.find(post => (post._id === postId));

    return (
      <MyVerticallyCenteredModal
        show={modalShow}
        title={post.title}
        body={post.body}
        onHide={this.modalClose}
      />
    );
  };
  render() {
    return (
      <div className="Posts">
        <h2>Posts</h2>
        <CardDeck>
          {this.state.posts.map(post => (
            <Card key={post._id + post.title}>
              <Card.Body>
                <Card.Title>"{post.title}"</Card.Title>
                <Card.Text>
                  {post.body}
                  <ButtonToolbar>
                    <Button
                      variant="primary"
                      onClick={() => this.modalClose(post._id)}
                    >
                      Read
                    </Button>
                  </ButtonToolbar>
                </Card.Text>
              </Card.Body>
              <Card.Footer>
                <Container>
                  <Row>
                    <Col>
                      <small className="text-muted">
                        Author: {post.author}{" "}
                      </small>
                    </Col>
                  </Row>
                </Container>
              </Card.Footer>
            </Card>
          ))}
        </CardDeck>
        {this.state.modalShow && this.renderModal()}
      </div>
    );
  }
}

I hope this helps you.

It is not perfect but something to help you figure out what was wrong initially.

Upvotes: 1

Related Questions