Reputation:
I have a form component in React that I use to send data to a pg database.
This is my form script :
import bodyParser from 'body-parser';
import React, { Fragment, useState } from 'react';
import RatingStar from '../components/rating'
const InputData = () => {
const [name, setName] = useState('')
const [rating, setRating] = useState('')
const onSubmitForm = async(e) => {
e.preventDefault();
try {
const payload = {
name,
rating
}
const response = await fetch("path", {
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify(payload)
});
window.location = "/";
} catch (error) {
console.log(error.message);
}
}
return(
<Fragment>
<div className="container">
<h1 className="text-center mt-5">RATE</h1>
<form className="mt-5" onSubmit={onSubmitForm}>
<div className="form-group">
<input
placeholder="Name"
type='text'
className='form-control'
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
<div className="form-group">
<div>
<RatingStar
value={}
/>
</div>
</div>
<div className="d-flex justify-content-center">
<button type="submit" className="d-flex btn btn-primary">Submit</button>
</div>
</form>
</div>
</Fragment>
);
}
export default InputData;
And this is my rating component :
import React, { useState } from 'react';
import { render } from 'react-dom';
import ReactStars from 'react-rating-stars-component'
import './style.css'
export default function RatingStar() {
const [rating, setRating] = useState("")
const secondExample = {
size: 50,
count: 5,
color: "black",
activeColor: "yellow",
value: 0,
a11y: true,
isHalf: true,
emptyIcon: <i className="far fa-star" />,
halfIcon: <i className="fa fa-star-half-alt" />,
filledIcon: <i className="fa fa-star" />,
onChange: (newValue) => {
console.log(`Example 2: new value is ${newValue}`);
setRating(newValue) // my try
}
};
return (
<div className="starComponent">
<ReactStars {...secondExample}
/>
</div>
);
}
So I was wondering how I could use newValue in the form component.
For now I tried using useState in the rating component but I can't access it from the form component to use it in my paylod.
Upvotes: 3
Views: 1383
Reputation: 9713
Instead of keeping same state (i.e rating value) in two components, keep it in form component and pass it as prop to the Rating component.
Rating component will notify the parent(Form) component whenever the value gets changed by calling a function. This is called Lifting state up.
Here is the code for Rating component which gets rating
and onRatingChange
props from the form component. onRatingChange
will be called with newValue
from inside onChange
function.
export default function RatingStar({ rating, onRatingChange }) {
const secondExample = {
size: 50,
count: 5,
color: "black",
activeColor: "yellow",
value: rating, // pass rating value here
a11y: true,
isHalf: true,
emptyIcon: <i className="far fa-star" />,
halfIcon: <i className="fa fa-star-half-alt" />,
filledIcon: <i className="fa fa-star" />,
onChange: (newValue) => {
console.log(`Example 2: new value is ${newValue}`);
// call onRatingChange function with new rating value
onRatingChange(newValue);
}
};
return (
<div className="starComponent">
<ReactStars {...secondExample} />
</div>
);
}
This is the code for Form component.
const InputData = () => {
const [name, setName] = useState('')
const [rating, setRating] = useState(0)
const onSubmitForm = async(e) => {
e.preventDefault();
try {
const payload = {
name,
rating
}
const response = await fetch("path", {
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify(payload)
});
window.location = "/";
} catch (error) {
console.log(error.message);
}
}
return(
<Fragment>
<div className="container">
<h1 className="text-center mt-5">RATE</h1>
<form className="mt-5" onSubmit={onSubmitForm}>
<div className="form-group">
<input
placeholder="Name"
type='text'
className='form-control'
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
<div className="form-group">
<div>
<RatingStar
rating={rating}
onRatingChange={(newRating)=>{
// update rating value here when you get a new value
setRating(newRating);
}}
/>
</div>
</div>
<div className="d-flex justify-content-center">
<button type="submit" className="d-flex btn btn-primary">Submit</button>
</div>
</form>
</div>
</Fragment>
);
}
export default InputData;
Upvotes: 2
Reputation: 8580
You need to keep the state in InputData
and pass it into RatingStar
with the change handler.
const InputData = () => {
const [rating, setRating] = useState(0);
const handleRatingChange = (newRating) => {
console.log(`setting rating to ${newRating}`);
setRating(newRating);
}
return (
<RatingStar value={rating} onChange={handleRatingChange} />
);
};
Then RatingStar
just uses the values from its parent.
const RatingStar = ({ value, onChange }) => {
const otherProps = {};
return (
<ReactStars {...otherProps} value={value} onChange={onChange} />
);
};
Here, RatingStar
is a controlled component
Upvotes: 1