Home > Software engineering >  Change this react class component into react hooks
Change this react class component into react hooks

Time:03-07

I am watching a tutorial of MERN Stack here in this video MERN. At the part of 1:41:16 - 1:47:01 I am trying to convert everything into react hooks and everything went well not until for the part of exercise-list component

So here is my code when I converted it into react-hook component.

import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import axios from 'axios'

const Exercise = item => {
    <tr>
        <td>{item.exercise.username} </td>
        <td>{item.exercise.description} </td>
        <td>{item.exercise.duration} </td>
        <td>{item.exercise.date.substring(0,10)} </td>
        <td><Link to={"/edit/"   item.exercise._id}> Edit</Link> | 
        <a href="#" onClick={e => {item.handledeleteExercise(item.exercise._id)}}> delete </a>
        
        </td>

    </tr>
}

function Exercises_List(props) {

    const [deleteExercise,setdeleteExercise] = useState()

    const [exercises,setexercises] = useState([])

    useEffect(() => {
        axios.get('http://localhost:4500/exercises/')
            .then(res => {
                setexercises([...exercises,res.data])
            })
            .catch(err => console.log(err))
    },[])

    const handledeleteExercise = (id) => {
        axios.delete('http://localhost:4500/exercises' id)
            .then(res => console.log(res.data));
        const filtered = exercises.filter((el) => el._id !== id)
        setexercises(filtered)
    }

    const exerciseList = () => {
        return exercises.map(currentexercise => {
            return <Exercise 
                exercise={currentexercise} 
                handledeleteExercise={e => handledeleteExercise(e)}
                key={currentexercise._id}></Exercise>
        })
    }

  
    return (
  
        <div>
            <h3> Logged Exercises</h3>
            <table className="table">
                <thead className="thead-light">
                    <tr>
                        <th>Username </th>
                        <th>Description </th>
                        <th>Duration </th>
                        <th>Date </th>
                        <th>Actions </th>
                    </tr>
                </thead>
                <tbody>
                    {exerciseList()}
                </tbody>
            </table>


        </div>
  
        )
}

export default Exercises_List

the only thing that confuses me here is const [deleteExercise,setdeleteExercise] = useState() As you see in the video of 1:41:22 .. I am very confused of how should I with deleteExercise to convert it in react-hooks.. I tried it something like this

deleteExercise = e => {
 ....
}
``` But I know that is out of the rules in react hooks...Another thing I look at here is this part of 
useEffect(() => {
    axios.get('http://localhost:4500/exercises/')
        .then(res => {
            setexercises({...exercises:res.data})
        })
        .catch(err => console.log(err))
},[])

once I show this in my output 



   {exerciseList()}

It gives me an error like this TypeError: exercises.map is not a function

I think I miss an idea here...I am also confused at the part of edit-exercises.component wherein it passing the props.match.params.id at part of 1:43:32..

Guys I am dying..I badly want to make simple full-stack-website but I just can't lol...the tutorials and my documentation learning are confusing specially the updates and documentation.

I cannot explain it all I am briefly sorry about that...What I want to just resolve here is the converting it into react-hooks since react class component is not really useful in my nature.

CodePudding user response:

I think your code is failing because of this:

setexercises({...exercises:res.data})

That statement stores an object in the exercises variable, and objects do not have a map method.

(Actually, I think that statement isn't valid syntax: you can't place three dots before a property name that also has a value. You could do this: ({ ...res.data }) or this ({ exercises: res.data }) -- although both will still break the same way because both store an object instead of an array. But these are at least valid ES6 syntax.)

I suspect the larger problem is that you're not thinking about your data correctly.

  • you've got a list of exercises
  • you want to be able to add and remove items on that list

It seems clear that you only need one array. That single array is what you should store using React's useState hook:

let [ exercises, setExercises ] = React.useState([])

Thus: exercises is the list (an array with a map method), and setExercises lets you completely overwrite that array. Pay attention to that last piece: the only tool provided by the useState hook is a tool that clobbers the whole list. That means your "add" and "remove" operations must accomplish their tasks using just that tool.

So, you have to finish the implementation of this function:

function addExercise( newExercise ) {
  /*
    STEP 1: calculate fresh array that contains
    all the current exercises plus newExercise.
  */
  let newList = [/* TODO */]

  /*
    STEP 2: overwrite current list using the
    only tool provided by useState. This updates
    the data *and* immediately re-renders the
    component with the new data.
  */
  setExercises(newList)
}

The same thinking applies to removing an exercise from the list:

function removeExercise( exerciseToRemove ) {
  /*
    STEP 1: calculate fresh array that contains
    all the current exercises minus exerciseToRemove.
  */
  let newList = [/* TODO */]

  /*
    STEP 2: overwrite current list using the
    only tool provided by useState.
  */
  setExercises(newList)
}

That same tool is also how you update the list when your API call returns:

useEffect(() => {
  axios.get('http://localhost:4500/exercises/')
  // this assumes that res.data is an array
  .then(res => setExercises(res.data))
  .catch(err => console.log(err))
}, [])

Also: your Exercises component probably doesn't parse. The curly braces that wrap the body need to be parentheses, or you need a return statement inside the body:

// bad!
const MyComp = props => { <div> thing </div> }

// good
const MyComp = props => ( <div> thing </div> )

// also good
const MyComp = props => { return (<div> thing </div>) }
  • Related