Home > Software design >  How to make component refetch data when other component mutates data?
How to make component refetch data when other component mutates data?

Time:10-22

Let's say for some reason we can not have the Parent component hold the set of Personnel data (or do any logic at all for this matter in the parent component) and we can not use atoms. Is there another way to make the AnotherComponentThatShowsBookedPersonnel know that it's time to refetch the data from API due to data mutated?


const Parent = () => {
   return (
       <BookPersonnel />
       <AnotherComponentThatShowsBookedPersonnel />
    )
}

const BookPersonnel = () => {
  const [personnel, setPersonnel] = useState<Personnel[]>([])
   useEffect(() => {
      const fetchPersonnel = async () => {
        const response = await fetchPersonnelBookings()
        setPersonnel(response)
      }  
    
    fetchPersonnel()
  }, [])

  const bookPersonnel = async (personnelId:number) => {
    const response = await bookPersonnelById(personnelId)
    setPersonnel(response)
  }

    return (
      <List of personnel here>
      <Button onClick={bookPersonnel}>Book personnel</Button>
    )
}

export const AnotherComponentThatShowsBookedPersonnel = () => {
  const [personnel, setPersonnel] = useState<Personnel[]>([])
   useEffect(() => {
      const fetchPersonnel = async () => {
        const response = await fetchPersonnelBookings()
        setPersonnel(response)
      }  
    
    fetchPersonnel()
  }, [])

  return (
      <List of booked personnel here>
    )
}

CodePudding user response:

Try eventbus model, and here is a naive implemention:

// useEventBus.ts
const eventBus:Record<string,(()=>void)[]> = {}

const useEventBus = (keyName:string)=>{
  const triggerEvent = ()=>eventBus[keyName]?.forEach(fn=>fn())
  const addCallback= (callback: ()=>void)=>{ 
    eventBus[keyName] =  eventBus[keyName]||([] as (()=>void)[])
    eventBus[keyName].push(callback)
    return ()=>{
      const index = eventBus[keyName].indexOf(callback)
      if(index!==-1){
       eventBus[keyName].splice(index,1)
      }
    }
  }

  return  {triggerEvent,addCallback}
}
// Where you mutate data
import useEventBus from 'useEventBus'
const BookPersonnel = () => {
  const [personnel, setPersonnel] = useState<Personnel[]>([])
  const {triggerEvent} = useEventBus('PERSONAL/CHANGED')

  const mutateData = ()=> {
    // after mutating data, create a event maunally
    triggerEvent()
    // 
  }
  
    return (
      <List of personnel here>
      <Button onClick={bookPersonnel}>Book personnel</Button>
    )
}

// where you want to be notified when data modified
import useEventBus from 'useEventBus'
const AnotherComponentThatShowsBookedPersonnel = () => {
  const [personnel, setPersonnel] = useState<Personnel[]>([])
  const {addCallback} = useEventBus('PERSONAL/CHANGED')
  useEffect(()=>{
    const cleanFn = addCallback( ()=>{
       // anything you want to do when data changed
    })
    // dispose this callback when component unmount
    return cleanFn;
  },[])
  //......

  return (
      <List of booked personnel here>
    )
}

And there are more tools like event-emitter you can choose to use.

But I still believe you could lift up your data up to shared parent of these components.

CodePudding user response:

Surprised no one has said this yet but use reacts useReducer/useContext hooks. useReducer would be your best option as it allows you to create dispatch functions to mutate the reducers state. Rather than defining personnel in multiple places, it can be defined as the reducers state. You wrap both components in a provider for that context reducer. Then in both components you can access the state value with a hook i.e const {personnel} = usePersonnelContext() or something like that. Because you are mutating one value, you don't have to kick either component to recognise things have changed. I'd go look at the react documentation on it though, will explain it better than I am!

CodePudding user response:

Have you tried passing personnel as a dependency in the useEffect

  • Related