I want to toggle font awesome icons on click. When the page is loaded i query the backend and find out whether a user is enrolled into a course or not, incase they are enrolled I show a tick icon, otherwise I show a coffee icon.
The end goal is have each individual icon change into the opposite when clicked. Currently when i click the icons, for example if i click a cup icon it not only changes into a tick but changes the rest of the cup icons into ticks too. How can I resolve this issue so that when clicked, only the clicked icon is affected?
Here is my code
Functional component
export const CourseCard = ({
video,
normaluser,
adminuser,
userauthenticated,
adminauthenticated,
handleUnroll,
handleEnroll,
enrolled,
unrolled
}) => (
<Grid item xs={6} md={4} lg={3}>
{(video.enrolled_students.includes(normaluser) &&
userauthenticated) ||
(video.enrolled_students.includes(adminuser) &&
adminauthenticated) ? (
<div className="enrol__button">
<div>
<a href="#" onClick={() => handleUnroll(video.slug)}>
<FontAwesomeIcon
icon={enrolled ? faCheckSquare : faCoffee}
/>
</a>
</div>
</div>
) : (!video.enrolled_students.includes(normaluser) &&
userauthenticated) ||
(!video.enrolled_students.includes(adminuser) &&
adminauthenticated) ? (
<div>
<a href="#" onClick={() => handleEnroll(video.slug)}>
<FontAwesomeIcon
icon={unrolled ? faCoffee : faCheckSquare}
/>
</a>
</div>
) : (
""
)}
</Grid>
Container
export class AllCourses extends React.Component {
constructor(props) {
super(props);
this.user = details(AUTHENTICATED);
this.admin = AdminDetails(AUTHENTICATED);
const token = localStorage.getItem("token");
let normaldetail = details(token);
this.normaluser = normaldetail.user_id;
let admindetail = AdminDetails(token);
this.adminuser = admindetail.user_id;
this.state = {
enrolled: true,
unrolled: true
};
}
handleEnroll = slug => {
this.props.dispatch(Enroll(slug));
this.setState({unrolled: !this.state.unrolled});
}
handleUnroll = slug => {
this.props.dispatch(Enroll(slug));
this.setState({enrolled: !this.state.enrolled});
}
render() {
const userauthenticated = this.user;
const adminauthenticated = this.admin;
const adminuser = this.adminuser;
const normaluser = this.normaluser;
const { allCourses } = this.props;
const {search, enrolled, unrolled} = this.state;
return (
<div className="container">
<Grid
container
spacing={3}
className="courses__row courses__row__medium"
>
{allCourses.map(video => (
<CourseCard
key={video.slug}
video={video}
enrolled={enrolled}
unrolled={unrolled}
handleEnroll={this.handleEnroll}
handleUnroll={this.handleUnroll}
normaluser={normaluser}
adminuser={adminuser}
userauthenticated={userauthenticated}
adminauthenticated={adminauthenticated}
/>
))}
;
</Grid>
</div>
);
}
It's because handleEnroll and handleUnroll set state that is shared across all the courses. From what you described it sounds like you want the state to actually be per course.
So you should alter AllCourses
slightly
handleEnroll = slug => {
// This should cause some change to the relevant course in allCourses
this.props.dispatch(Enroll(slug));
}
handleUnroll = slug => {
// This should cause some change to the relevant course in allCourses
this.props.dispatch(Enroll(slug));
}
// Delete this
this.state = {
enrolled: true,
unrolled: true
};
And then change the CourseCard mapping to use the properties from video
rather than the ,now eliminated, AllCourses state.
{allCourses.map(video => (
<CourseCard
key={video.slug}
video={video}
enrolled={video.enrolled}
unrolled={video.unrolled}
handleEnroll={this.handleEnroll}
handleUnroll={this.handleUnroll}
normaluser={normaluser}
adminuser={adminuser}
userauthenticated={userauthenticated}
adminauthenticated={adminauthenticated}
/>
))}
Since you're checking in the Grid
component whether the current user is enrolled or not (by seeing if that video.enrolled_students
array includes the current user), then those enrolled
and unrolled
flags don't seem necessary anymore.
So in Grid
you should be able to change the first <FontAwesomeIcon />
call to just:
<FontAwesomeIcon icon='faCheckSquare' />
and the second one to
<FontAwesomeIcon icon='faCoffee' />
Also, you have a typo in AllCourses where you're calling this.props.dispatch(Enroll(slug));
in both handleEnroll
and handleUnroll
where it should most probably be Unroll(slug)
in the second one.
You can instead a conditional on a boolean try to compare current card key to checked card key
<FontAwesomeIcon icon={this.props.checkedCard == this.props.key ? faCoffee : faCheckSquare} />
and in your container :
handleEnroll = slug => {
this.props.dispatch(Enroll(slug));
this.setState({checked: this.props.key});
}
and :
<CourseCard
key={video.slug}
video={video}
checkedCard={this.state.checkedCard}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.