I am new to react Hooks (I should say: haven't even started with them yet), but I need assistance with this small problem. This component renders stars and allows a user to select the rating. I want to pass the {starSelected} value from this component to a parent component.
import React, { useState } from "react";
import "./styles.css";
const Star = ({ selected = false, onClick = f => f }) => (
<div className={selected ? "star selected" : "star"} onClick={onClick} />
);
const StarRating = ({ totalStars }) => {
const [starsSelected, selectStar] = useState(0);
return (
<div className="star-rating">
{[...Array(totalStars)].map((n, i) => (
<Star
key={i}
selected={i < starsSelected}
onClick={() => selectStar(i + 1)}
/>
))}
<p>
{starsSelected} of {totalStars} stars
</p>
</div>
);
};
I would appreciate any help!!!
Parent Component
class RatingNFeedback extends Component {
constructor(props) {
super(props);
this.state = {
user: {},
modal: false,
ratings: '',
feedback: '',
feedbackTitle: '',
errors: {}
};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState(prevState => ({
modal: !prevState.modal,
ratings: '',
feedback: '',
feedbackTitle: ''
}));
}
handleRating = (assetId, accessToken) => {
const {rating, feedback, feedbackTitle} = this.state;
const ratings = {
rating,
feedbackTitle,
feedback,
asset: assetId
};
this.props.addRatingNComment(ratings, accessToken);
this.toggle();
};
onChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
isModalOpen() {
return this.state.modal;
}
render() {
const {ratingCount, commentCount, assetId, accessToken} = this.props;
let stars = [];
//loop 5 times for stars
for (let i = 1; i <= 5; i++) {
let path = require('../../assets/rateFull.svg');
if (i > ratingCount) {
path = require('../../assets/RateZero.svg');
}
stars.push(<img src={path} alt="" className="card-category-rating" />);
}
let userpic = defaultPic;
if (this.props.user) {
userpic =
'http://people.com/User%20Photos/Profile%20Pictures/' +
this.props.user.profile +
'_LThumb.jpg';
}
return (
<React.Fragment>
<Modal
isOpen={this.isModalOpen()}
toggle={this.toggle}
//style={{height: '500px', width: '500px'}}
centered
className="modal"
animation="true"
>
<ModalHeader toggle={this.toggle} className="modal-header">
<span className="modal-title"> How would you rate this report? </span>
</ModalHeader>
<ModalBody className="modal-body ">
<div className="rating-modal-header">
{' '}
<div className=" image-name-box">
<div className="circular-landscape image-box">
<img src={userpic} alt="Employee Image" className="user-profile" />{' '}
</div>
<div className="name-box">
{' '}
<p className="normal-text-2">
{' '}
{`${this.props.userName} ${this.props.familyName}`}{' '}
</p>{' '}
<p className="small-text-2 "> Your review will be posted on Our Website.</p>
</div>
</div>{' '}
</div>
<div className="heading3">Your Ratings</div>
<StarRating totalStars={5} />
<FormTextInput
label="Your Feedback:"
name="feedbackTitle"
value={this.state.feedbackTitle}
onChange={this.onChange}
placeholder="Title goes here..."
type="text"
/>
<FormTextInput
//label="Your Feedback:"
name="feedback"
value={this.state.feedback}
onChange={this.onChange}
placeholder="Write your feedback here..."
type="textarea"
/>
</ModalBody>
<ModalFooter>
<Button
color="primary"
onClick={() => this.handleRating(this.props.assetId, this.props.accessToken)}
>
Submit
</Button>{' '}
<Button color="secondary" onClick={this.toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
</React.Fragment>
);
}
}
First, you'll need to create two components, one parent and one child. Next, you'll import the child component in the parent component and return it. Then you'll create a function and a button to trigger that function. Also, you'll create a state using the useState Hook to manage the data.
In other words, data flows only one way, from the parent to the child component, in the case of React. The reverse of that, i.e. passing data from the child to the parent is not possible, at least not in theory. Data can be passed from the parent to the child component via props.
To pass data from child to parent component in React: Pass a function as a prop to the Child component. Call the function in the Child component and pass the data as arguments. Access the data in the function in the Parent .
What you should do is: On the parent you have [state, setState] On the current component pass setStat as a prop to child component and then from child component pass setState as a prop to grandchild component. Then on grandchild component you can do something like: props. setState(array).
This can be done by passing a function from the parent component into the child component and then calling that to update the state in the parent. You could also use this method to completely manage the state in the parent if you wanted to, but this example doesn't do that.
Parent component:
import React, { useState } from "react";
import "./styles.css";
const ParentComponent = () => {
const [selectedStar, setSelectedStar] = useState();
const updateStars = (star) => {
setSelectedStar(star);
}
return (
<StarRating
totalStars={10}
onStarUpdate={updateStars}
/>
);
}
Then the star component:
import React, { useState } from "react";
import "./styles.css";
const Star = ({ selected = false, onClick = f => f }) => (
<div className={selected ? "star selected" : "star"} onClick={onClick} />
);
const StarRating = ({ totalStars, onStarUpdate }) => {
// you should call your 'setter' `set` and then the name of the const
// rather than 'selectStar'
const [starsSelected, setStarsSelected] = useState(0);
const handleOnClick = (index) => {
setStarsSelected(index + 1);
// this next line will update the state in the parent component
onStarUpdate(index + 1);
}
return (
<div className="star-rating">
{[...Array(totalStars)].map((n, i) => (
<Star
key={i}
selected={i < starsSelected}
onClick={() => handleOnClick(i)}
/>
))}
<p>
{starsSelected} of {totalStars} stars
</p>
</div>
);
};
By passing a function from the parent into the child, and then calling it in the child, you can update the state in the parent.
Like I say you could also use this to completely handle the state, then you could write the StarRating like this:
<StarRating
totalStars={10}
onStarUpdate={updateStars}
selectedStar={selectedStar}
/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With