I have just graduated a bootcamp and working on my first project in React. I have a fetch request that renders back an array of objects from my Rails DB. They are books. And each book has specific reviews. I therefore have all my books rendered in my array as per below and i have another fetch request for the individual book that is clicked on so it opens up more details about it like author, description, etc along with its reviews. Everything is great up until the point when i click on another book. Then the reviews from my last clicked book will get rendered in all the books that have been opened before it. I do appreciate is the state that is correctly rendered but i am wondering if there is a way of persisting each state per individual book? I am using Rails 5.1.4 with WebPacker not react-rails, this is my code below: Thank you so very much for your kind assistance!
var PropTypes = require ('prop-types')
var Reviews = require ('./reviews.jsx')
var ReactStars = require ('react-stars')
var BuyButton = require ('images/buyButton.jpg')
var MainBasket = require('./mainBasket.jsx');
var reviewsArray = [];
class EachBook extends React.Component {
constructor(props){
super(props);
this.state = {
reviews: reviewsArray
}
}
getReview(bookId){
fetch(`http://localhost:3000/books/${bookId}/reviews`,{
method: 'POST',
mode: 'cors',
body: JSON.stringify({comment: this.refs.comment.value}),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-Token' : this.props.parent.props.parent.props.csrf
}),
credentials: 'same-origin'
}).then(response => response.json())
.catch(error => alert("There is something wrong with this request"))
.then( response => {
this.state.reviews.push(response);
this.setState(this.state)
})
}
render(){
return(
<div>
<MainBasket items={this.state.items} total={this.state.total} />
<div className="container">
{this.props.singleBook.map(indBook =>
<div className="indBook" key={indBook.id}>
<h1>{indBook.title}</h1> <br />
<h2>{"Author: " + indBook.author}</h2> <br />
<h4>{"Genre: " + indBook.genre}</h4>
<h4>{"Price: " + indBook.price}£</h4>
<img src={indBook.image.url} />
<div className="button"><img src={BuyButton} onClick={function(){this.addItemToBasket(indBook.id)}.bind(this)}/></div>
<div className="description">{indBook.description}</div>
<h3> Reviews for {indBook.title} :</h3>
<Reviews allReviewsTogether={reviewsArray} />
<div>
{this.props.singleBookReviews.map(eachReview =>
<div key={"eachReview-" + eachReview.id}>
<h5> Left by {eachReview.user.name} on {eachReview.created_at.slice(0,10)}</h5>
<div>{eachReview.comment}</div>
</div>
)}
<h4>Leave a new review</h4>
<textarea ref="comment" type="text" placeholder='Tell us your thoughts '></textarea>
<button onClick={ function(){this.getReview(indBook.id)}.bind(this) } >Submit</button>
</div>
</div>
)}
</div>
</div>
)
}
}
module.exports = EachBook;
var React = require ('react')
var ReactDOM = require ('react-dom')
var PropTypes = require ('prop-types')
class Reviews extends React.Component {
constructor(props){
super(props);
}
render(){
return(
<div className="bookReview">
{this.props.allReviewsTogether.map( review =>
<div key={"review-" + review.id}>
{review.comment}
</div>
)}
</div>
)
}
}
module.exports = Reviews;
Please note the screenshot in the link below: my first book Self Reliance which has reviews gets rendered ok i can see them but when i click on the second one Huckleberry Finn which does not have any reviews yet, it updated the Self Reliance one with no reviews as well. I cannot post a second link with the first image as well unfortunately i am only allowed to one picture. Many thanks again!
books component which renders each book:
import React, { Component } from 'react';
import EachBook from './eachBook';
class Books extends React.Component {
constructor(props){
super(props);
this.state = {
individualBook: [],
bookReviews: []
}
}
bookDetails(bookId){
fetch(`http://localhost:3000/books/${bookId}`)
.then(response => response.json())
.then(book => {
this.state.individualBook.push(book);
this.setState(this.state);
})
}
render(){
return(
<div className="container">
<EachBook singleBook={this.state.individualBook} parent={this} />
<div className="row">
{this.props.allBooks.map(book =>
<div className="col-sm" key={book.id} id={"bookId-" + book.id}>
<h1><a href="">{book.title}</a></h1>
<img src={book.image.url} className="image-style" />
<button onClick={function(){this.bookDetails(book.id)}.bind(this)}> Read More </button>
</div>
)}
</div>
</div>
)
}
}
export default Books;