React: infinite render on useEffect only when using an internal component

I have this following code Parent and DataFilter.

Parent.js

const Parent = () => {
  const [filteredData, setFilteredData] = useState()

  ...

  const Filter = () => {
    return (
      <div>
        <h2>Filter your data</h2>
        <DataFilter data={filteredData} updateFilter={setFilteredData} />
        <Result data={filteredData} />
      </div>
    )
  }


  return (
    <div>
      <h1>Header</h1>
      <Filter />
    </div>
  )
}

DataFilter.js

const DataFilter = ({ data, updateFilter }) => {
  const [name, setName] = useState(defaultFilters.name)
  const [age, setAge] = useState(defaultFilters.age)
  
    ...(filter logic using data)
  
  useEffect(() => {
    updateFilter({ name, age })
  }, [name, age])
}

Here, I receive Maximum update depth exceeded aka infinite rendering, which I kind of know why.

  1. Parent and DataFilter get rendered
  2. DataFilter triggers Parent‘s setFilteredData in useEffect
  3. Parent gets rerendered because of setFilteredData
  4. Parent being rerendered triggers child component DataFilterrerender
  5. Repeat from No.2

But, this only started happening only after I extracted Filter in ‘Parent’ as an inner component… I know it’s weird but it was working fine when Parent was like this


const Parent = () => {
  const [filteredData, setFilteredData] = useState()

  ...

  return (
    <div>
      <h1>Header</h1>
        <div>
          <h2>Filter your data</h2>
          <DataFilter data={filteredData} updateFilter={setFilteredData} />
          <Result data={filteredData} />
        </div>
    </div>
  )
}  

Does anyone know why the infinite rendering happens only when it’s as an inner component?

I tried using useCallback for setFilteredData but it didn’t work.

Also what should I do to prevent the infinite render if I want to keep it as a component rather than directly writing everything in a return()?