Search code examples
javascriptreactjsreact-hooksuse-effectuse-state

Re-Calling a react hook after a function is executed


I am new to react hooks and I have a hook function which receives a series of data from an API to be shown in a list:

function useJobs () {
  const [jobs, setJobs] = React.useState([])
  const [locations, setLocations] = React.useState({})
  const [departments, setDepartments] = React.useState({})
  const [tags, setTags] = React.useState({})

  React.useEffect(() => {
    fetchJSON('/api/jobs/list-jobs', { headers: headers })
      .then(setJobs)
  }, [])
  React.useEffect(() => {
....
  return [jobs, locations, departments, tags]
}

and I have another function which deletes the jobs when a button is pressed:

function DeleteJob (jobid) {
  console.log('deletejob fired')
  console.log(jobid)
  axios({
    method: 'delete',
    url: '/api/jobs/delete-job/' + jobid,
    headers: headers
  })
}

...

export default function Jobs () {
  const classes = useStyles()
  const [jobs, locations, departments, tags] = useJobs()
  return (
      ...
{jobs.map(job => (
......
 <IconButton aria-label='delete' style={{ color: 'red' }} variant='outlined' onClick={() => DeleteJob(job.id)}>
                     <DeleteIcon />
 </IconButton>

the problem is that the DeleteJob function executes correctly and my job gets deleted, but my screen doesnt get updated in real time and it needs refreshing to show the new data. how can I make my useJob() hook receive the new data (jobs) after the DeleteJob function is executed?


Solution

  • Your DeleteJobs function also needs to delete the job value from state as your data from server is only fetched on initial render. For that you can expose a method from custom hook and use it when calling DeleteJobs

    function useJobs () {
      const [jobs, setJobs] = React.useState([])
      const [locations, setLocations] = React.useState({})
      const [departments, setDepartments] = React.useState({})
      const [tags, setTags] = React.useState({})
    
      const deleteJob = (id) => { // function that removes job from state
          setJobs(prevJobs => prevJobs.filter(job => job.id !== id));
      }
      React.useEffect(() => {
        fetchJSON('/api/jobs/list-jobs', { headers: headers })
          .then(setJobs)
      }, [])
    
      ....
      return [jobs, locations, departments, tags,deleteJob]
    }
    
    
    function DeleteJob (jobid) {
      console.log('deletejob fired')
      console.log(jobid)
      axios({
        method: 'delete',
        url: '/api/jobs/delete-job/' + jobid,
        headers: headers
      })
    }
    
    export default function Jobs () {
      const classes = useStyles()
      const [jobs, locations, departments, tags, deleteJob] = useJobs()
      return (
          ...
          {jobs.map(job => (
          ......
           <IconButton 
              aria-label='delete'
              style={{ color: 'red' }} 
              variant='outlined' 
              onClick={() => { 
                  DeleteJob(job.id); 
                  deleteJob(job.id); // locally delete from state
              }}
           >
               <DeleteIcon />
           </IconButton>
    
          ...
      )
    }