'Is it possible to pseudo render a fragment so it can create its children for you to access?

I have a masonry layout component that looks somewhat like this:

function MasonryLayout({ columns, gap, children, ...rest }: Props) {
  const columnWrapper: any = {};
  const result = [];

  for (let i = 0; i < columns; ++i) {
    columnWrapper[`column${i}`] = [];
  }

  React.Children.forEach(children, (child, i) => {
    const columnIndex = i % columns;
    columnWrapper[`column${columnIndex}`].push(
      <div css={{ marginBottom: `${gap}px` }} key={i}>
        {child}
      </div>
    );
  });

  for (let i = 0; i < columns; ++i) {
    result.push(
      <div
        css={{
          marginLeft: `${i > 0 ? gap : 0}px`,
          flex: 1,
        }}
        key={i}
      >
        {columnWrapper[`column${i}`]}
      </div>
    );
  }

  return (
    <div tw="flex" {...rest}>
      {result}
    </div>
  );
}

Inspiration was taken from here https://medium.com/the-andela-way/how-to-create-a-masonry-layout-component-using-react-f30ec9ca5e99

I also have an InfiniteScroller component that looks somewhat like this:

const SearchResultPage = ({ variables, onLoadMore, isLastPage, query }) => {
  const [result] = useQuery({ query, variables });

  const { data, fetching, error } = result;

  const searchResults = data?.search;

  return (
    <SearchResultsFragment>
      {searchResults && searchResults.nodes.map(info => (
        <li>
           <SearchResult info={info}/>
        </li>
      )}
      {isLastPage && searchResults.pageInfo.hasNextPage && (
            <BoundaryLIToTriggerFetchingMore/>
      )}
    </SearchResultsFragment>
  );
};

const InfininiteScroller = ({query}) => {
  const [pageVariables, setPageVariables] = useState([
    {
      query,
      first: limit,
      after: '',
    },
  ]);

  return (
    <InfininiteScrollerFragment>
      {pageVariables.map((variables, i) => (
        <SearchResultPage
          key={'' + variables.after}
          query={query}
          variables={variables}
          isLastPage={i === pageVariables.length - 1}
          onLoadMore={after =>
            setPageVariables([...pageVariables, { after, first: limit, query }])
          }
        />
      ))}
    </InfininiteScrollerFragment>
  );
};

Inspiration was taken from here: https://github.com/FormidableLabs/urql/blob/main/examples/with-pagination/src/PaginatedNpmSearch.jsx

If I do

 return <MasonryLayout>
     <InfininiteScroller query={query}/> 
</MasonryLayout> 

I get one column in the Masonry layout because it only sees InfininiteScrollerFragment as a child which then spawns SearchResultsPages after being rendered

However, if I query for the search results another way by using hooks and a results state, I can pass the results directly like this and it works as expected. This makes sense because now MasonryLayout can see all the children.

return <div>
    <MasonryLayout>
     {searchResult.map((info) => (
        <li>
         <SearchResult info={info}/>
        </li>
      )}
    </MasonryLayout> 
    <BoundaryDivToTriggerFetchingMore/>
</div>

Question: Is it possible to somehow access children of a child by pseudo rendering the said child so that it can create its children? Or is there a better way I should go about achieving this?

Passing the results directly is somewhat okay however it introduces inconsistency in my code and also causes unnecessary rerenders, resulting in unwanted flashing.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source