Skip to content

Recursive React components & un-mounting/ re-rendering of components #69

Closed
@bentongxyz

Description

@bentongxyz

Hi there, when I try to create recursive react components, e.g. a folder structure UI:

RecursiveFolderComponent
├── RecursiveFolderComponent
│   ├── RecursiveFolderComponent
│   ├── RecursiveFolderComponent
├── RecursiveFolderComponent
    ├── RecursiveFolderComponent
    │   ├── RecursiveFolderComponent
    ├── RecursiveFolderComponent

I am hit with problems of all children components un-mounting and re-rendering (and React.memo also fails to work) when the parent component's state is updated.

I can make it work by using impure unsafePerformEffect like so:

recursiveFolder  ReactComponent { folderId  Int }
recursiveFolder = unsafePerformEffect $ memo' eq $
--                      ^ If I do not use `unsafePerformEffect`, 
--                        subfolder components will keep unmount and re-render
  reactComponent "RecursiveComponent" \props -> React.do
    ... 
    let
      arrOfSubFolders = const (element recursiveFolder { folderId: props.folderId - 1 })
        <$> (mkRows props.folderId)
    pure $ ...
          , React.fragment arrOfSubFolders
     ...

I have made a minimal reproducible code at:

If I do not use unsafePerformEffect, the children sub components will always un-mount and re-render, and I have to use unsafeRenderEffect in the middle of the component anyway (see below):

I think the issue is (to quote your succinct comment):

React uses function instances as component identity. ... Creating component functions during render results in forced unmouting and remounting of the entire tree below that component...

Originally posted by @megamaddu in #12 (comment)

Is there no other way to achieve memoization of recursive children components in Purescript without using unsafePerformEffect/ unsafeRenderEffect that might have arbitrary side-effect?

Is this one of the cases that Javascript/React refuses to play nicely with pure functional approach?

Thank you for reading through this long-winded issue.

Lastly, this is a Codepen | Typescript Implementation of how I would write it in "normal" Typescript, for refererence.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions