Arjun Kashyap
Arjun Kashyap

Reputation: 663

How to fix "same prop getting passed to children" in react js?

So I am preety new to react js. I am creating a blog app. I am storing blog data in the state and passing it to the children component. In the following piece of the code, I have Feeds component where I am fetching data from the json and storing it in the state. I a passing the data to children component Feed through props. Now I have an article component which is the child of the Feed which opens as a modal. The problem however is no matter which Feed I click on, it opens the same article (whichever was last enetered).

Feeds.jsx

import React, { Component } from "react";
import axios from "axios";
import Feed from "./Feed";

class Feeds extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoaded: false,
      feeds: []
    };
  }

  componentDidMount() {
    axios
      .get("http://localhost:5000/api/items")
      .then(res => res.data)
      .then(data => {
        this.setState({ isLoaded: true, feeds: data });
      console.log("data " + data);
     })
      .catch(err => console.log("Error !! : " + err));
  }

  render() {
    let { isLoaded, feeds } = this.state;

    if (!isLoaded) {
      return (
        <div>
          <h4> Loading ..</h4>
        </div>
      );
    } else {
      return (
        <div className="container-fluid">
          <Feed feedData={feeds} key={feeds.id} />
        </div>
      );
    }
  }
}
// const style for class Feed

export default Feeds;

Feed.jsx

import React, { Component } from "react";
import "bootstrap/dist/css/bootstrap.css";
import Article from "../component/Article";

class Feed extends Component {
  constructor(props) {
    super(props);
    this.state = {
      showModal: false
    };
  }

  showModal() {
    this.setState({ showModal: true });
  }

  hideModal() {
    this.setState({ showModal: false });
  }

  render() {
    console.log("Id: " );
    console.log(this.props.feedData, "feedData");
    let modalClose = () => this.setState({ showModal: false });
    return (
      <div className="container-fluid">
        <ul className="list-group" key={this.props.feedData.id}>
          {this.props.feedData.map(feed => (
            <li
              className="list-group-item"
              style={styles.container}
              key={feed.id}
            >
              <div className="container">
                <div className="col-md-12">
                  <button
                    type="button"
                    className="btn btn-default"
                    onClick={() => this.showModal()}
                  >
                    <h3 style={styles.heading}>{feed.title} </h3>
                  </button>
                  <p>by - {feed.author}</p>
                  <p>{feed.subTitle}</p>
                  <div>
                    <span className="badge">Posted {feed.date}</span>
                    <div className="pull-right">
                      <button className="btn btn-primary">Upvote</button>{" "}
                      <button className="btn btn-info">Comment</button>{" "}
                      <button className="btn btn-danger">Report</button>{" "}
                    </div>
                  </div>
                  <br />

                  <Article
                    key={feed.id}
                    show={this.state.showModal}
                    onHide={modalClose}
                    data={feed}
                  />
                </div>
                <hr />
              </div>
            </li>
          ))}
        </ul>
      </div>
    );
  }
}

Article.jsx

import React, { Component } from "react";
import { Button, Modal } from "react-bootstrap";

class Article extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  render() {
    console.log("This is working. Visibility: " + this.props.visible);
    console.log("This is the id of the feed: " + this.props.key);
    return (
      <div className="article">
        <Modal
          {...this.props}
          size="lg"
          aria-labelledby="contained-modal-title-vcenter"
          centered
        >
          <Modal.Header closeButton>
            <Modal.Title id="contained-modal-title-vcenter">
              {this.props.data.title}
            </Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <h4> {this.props.data.subTitle} </h4>
            <p>{this.props.data.content}</p>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={this.props.onHide}>Close</Button>
          </Modal.Footer>
        </Modal>
      </div>
    );
  }
}

export default Article;

I have setup the title in Feed.jsx as a button to open modal. Each Feed is opening the same article and on console. it shows that the props id is undefined..

console:

Id: Feed.jsx:22
(2) […]
​
0: Object { _id: "5cf24b53431f5f089496354b", author: "Arjun", title: "Liberalism and Loyality", … }
​
1: Object { _id: "5cf7a4b26332500efc0d1919", author: "Kapil Goel", title: "Made my first website", … }
​
length: 2
​
<prototype>: Array []
 feedData Feed.jsx:23
Warning: Each child in a list should have a unique "key" prop.

Check the render method of `Feed`.for more information.
    in li (at Feed.jsx:29)
    in Feed (at Feeds.jsx:38)
    in div (at Feeds.jsx:37)
    in Feeds (created by Context.Consumer)
    in Route (at App.js:14)
    in div (at App.js:11)
    in App (at src/index.js:10)
    in Router (created by BrowserRouter)
    in BrowserRouter (at src/index.js:9) index.js:1375
    e index.js:1375
    React 5
    render Feed.jsx:26
    React 13
    componentDidMount Feeds.jsx:19
This is working. Visibility: undefined Article.jsx:10
This is the id of the feed: undefined Article.jsx:11
This is working. Visibility: undefined Article.jsx:10
This is the id of the feed: undefined Article.jsx:11
feedData is Array:  false Feeds.jsx:20
GEThttp://localhost:3000/sockjs-node/432/v3s4dxpn/websocket

Upvotes: 0

Views: 157

Answers (2)

Ravi Heer
Ravi Heer

Reputation: 103

We can't use the key keyword as a custom prop in react component because it is pre-reserved in react.

Mostly, key keyword is used in iteration to identify the element in the loop or provide a unique identity to element in the loop.

You can use feedId as a prop,

<Article
  // key={feed.id}
  feedId={feed.id} // you can use feedId instead of key
  show={this.state.showModal}
  onHide={modalClose}
  data={feed}
/>

Also in Article.jsx, You are using this.props.visible to console but you have not passed it as a prop.

Upvotes: 3

tabulaR
tabulaR

Reputation: 310

    axios
  .get("http://localhost:5000/api/items")
  .then(res => res.data)
  .then(data => {
    this.setState({ isLoaded: true, feeds: data });
  })
  .catch(err => console.log("Error !! : " + err));

If you could console.log the data before you put it in setState. It is important to know whether data is in array format or not. You either cannot access feeds.id for the "key" prop for the Feed component in Feeds or you might have a bigger problem because you serve the Feed component an Object even tho it expects an array

Upvotes: 0

Related Questions