Search code examples
reactjsreact-component

Change state of buttons


Conditional rendering buttons doesn't work

I tried to change the state of the buttons and add instead another component but none got worked

    /// This is the button component


   const AddToList: React.FC<IAddToListProps> = (props) => {
   let [showBtn, setShowBtn] = useState(true);
     const classes = useStyles(props);
     let addToList = () => {
    fetch(`http://127.0.0.1:3000/${props.action}/${props.id}`, {method: 
 'post'})
         .then((response) => {
         console.log(response);
     });
   }
return (
  <div>
    {
      showBtn ?
      <Button
      onClick={addToList}
      variant="contained" 
      color="primary" 
      className={classes.button}>
        {props.label}
      </Button>
      : null
    }
</div>
    );



   //This is the movieCard component


   export default function MovieCard() {
const [movieTitle, setMovieTitle] = useState('lorem ipsum');
const [year, setYear] = useState('1999');

const classes = useStyles();

return (
    <Card className={classes.card}>
        <CardActionArea>
            <CardMedia
                className={classes.media}
                image='#'
                title="anotherTitle"
            />
            <CardContent>
                <Typography gutterBottom variant="h5" component="h2">
                    {movieTitle}
                </Typography>
                <Typography variant="body2" color="textSecondary" component="p">
                    {year}
                </Typography>
                <AddToList 
                id={10} 
                label={'Add To Watch'} 
                action={'towatch'}
                />
                <AddToList 
                id={10} 
                label={'Add To Seen'} 
                action={'watched'} />
            </CardContent>
        </CardActionArea>
        <CardActions>

        </CardActions>
    </Card>
);

Expected results: When I click "Add to Watch" button, "Add to Seen" must be removed and "Add to Watch" must be transformed in "Remove from watch list"


Solution

  • I would split up the code between logic and presentation. As you already reused AddToList it's just a visual component and should not contain any logic.

    So I would move all logic to one component and then use the state to render the correct presentation:

    const AddToList: React.FC<IAddToListProps> = props => {
      const classes = useStyles(props);
      return (
        <div>
            <Button
              onClick={props.onClick}
              variant="contained"
              color="primary"
              className={classes.button}
            >
              {props.label}
            </Button>
        </div>
      );
    };
    

    With this you can provide any function which is called when clicking the button and you have a multipurpose component for resuse anywhere else. So a more generic name may be useful.

    export default function MovieCard() {
      const [movieTitle, setMovieTitle] = useState("lorem ipsum");
      const [year, setYear] = useState("1999");
    
      const [watched, setWatched] = useState(false);
    
      const classes = useStyles();
    
      const addToList = (action, id) => {
        fetch(`http://127.0.0.1:3000/${action}/${id}`, {
          method: "post"
        }).then(response => {
          console.log(response);
        });
      };
    
      return (
        <Card className={classes.card}>
          <CardActionArea>
            <CardMedia className={classes.media} image="#" title="anotherTitle" />
            <CardContent>
              <Typography gutterBottom variant="h5" component="h2">
                {movieTitle}
              </Typography>
              <Typography variant="body2" color="textSecondary" component="p">
                {year}
              </Typography>
              {!watched && (
                <AddToList
                  label={"Add To Watch"}
                  onClick={() => { addToList("towatch", 10); setWatched(true)} }
                />
              )}
              {watched && (
                <AddToList
                  label={"Add To Seen"}
                  onClick={() => addToList("watched", 10)}
                />
              )}
            </CardContent>
          </CardActionArea>
          <CardActions />
        </Card>
      );
    }
    

    As you can see the MovieCard is now handling the whole logic of calling backend functions and also cares about showing the correct button. With this basic idea you can advance even more with loading the correct watched state and not starting with false or any other thing.