简体   繁体   中英

Toggle font-awesome icon on click in react

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM