1

I'm struggling for days now with a setup I'd thought would be easy and reusable:

I'm building an App with Ionic 5 + React, which has kind of a news feed, where multiple kind of content comes together. But not exactly the way like in Facebook, it has different sections for each kind of content (like events, news, etc.).

They all act similar: each section has a title, shows the first n items and then a "Show more" link. Of course a click on one of these items immediatly brings the user to the detail page. But a click on "Show more" should bring the user to a page with only that specific list in expanded form (instead of let's say the first 3 items there should be 50 and when reaching the end of that list it should load the next 50 and so on).

Because the APIs that deliver each kind of content use different structures, the page on which that "section component" is embedded passes two functions, sourceFn and mapFn, to that component. sourceFn handles loading of that n items while mapFn takes an item and maps that API data structure to the fields that are needed for the reused section component to render it's list items.

So far so good, it works. But I'm stuck at the "Show more" link. Because here that embedded section redirects to another page, which dynamically displays the expanded list, it need's to know the corresponding two functions sourceFn and mapFn. I tried many approaches (like https://stackoverflow.com/a/52064362) but every single one failed. Some times it says that somewhere props is unknown, but mainly because of DataCloneError: The Object could not be cloned

I'm happy for every hint, how it could be done (or done better)


Here are some approaches I tried: (Please let me know in a comment, whether to post more code. I don't want to spam 0:) )

<Link to={'/page/list'+ id} id={id} title={title} sourceFn={sourceFn} mapFn={mapFn}>
    <IonButton slot="end" size="small" fill="clear" routerDirection="forward">
        Show more
        <IonIcon icon={chevronForwardOutline} slot="end" />
    </IonButton>
</Link>
<Link to={{
    pathname: '/page/list'+ id,
    state: {id: id, title: title, sourceFn: sourceFn, mapFn: mapFn}
}}>
    <IonButton slot="end" size="small" fill="clear" routerDirection="forward">
        Show more
        <IonIcon icon={chevronForwardOutline} slot="end" />
    </IonButton>
</Link>

and the Route in App.tsx:

<Route
    exact={true}
    path={"/page/list/:sectionid"}
    render={(props) =>
        <List
            id={props.location.state.id}
            title={props.location.state.title}
            sourceFn={props.location.state.sourceFn}
            mapFn={props.location.state.mapFn}
        />}
/>

and also simply

<Route exact={true} path={"/page/list/:sectionid"} component={List} />
Robert
  • 378
  • 6
  • 19

2 Answers2

1

I think this calls for Context.

The parent component can have a context at the level where sourceFn and mapFn come from:

const SomeContext = React.createContext()

export const useContextName = React.useContext(SomeContext)

<SomeContext.Provider value={{ sourceFn, mapFn }}>
  ...your routes here...
</SomeContext.Provider>

then in your List component, you can do:

import { useContextName } from 'wherever/you/are/exporting/from'

const List = (...your props ...) => {
   const { sourceFn, mapFn } = useContextName()
   ... the rest of your component ...
}

and as you said, your route would simply be:

<Route exact={true} path={"/page/list/:sectionid"} component={List} />
Arber Sylejmani
  • 1,963
  • 1
  • 13
  • 19
  • I‘m sorry I’m not yet familiar with Context, but may I ask: is there no danger of a conflict when reusing that component multiple times on the same page with different functions? Doesn’t that overwrite that context? – Robert May 04 '20 at 23:02
  • 1
    Context means just passing data down the tree without having to specifically pas them via props, you can do whatever, you can pass the reference of any function back to the Context provider and provide it down for the children. I don't think any of us here can give you a complete ready to go solution. As you an see from two answers already, the suggestion/hint you're looking for is Context! – Arber Sylejmani May 06 '20 at 14:08
0

I would suggest the React.Context approach but you can also just pass the names of the functions as parameter names like this

<Route exact={true} 
  path={"/page/list/:mapFuncName/:sourceFuncName/:sectionid"} 
  component={List} />

In Your function helper library map all of the functions so they can be accessed by the specific name.

mapFuncMap : {
  func1 : ()=> {}
  func2 : ()=> {}
  func3 : ()=> {}
}

sourceFuncMap : {
  func1 : ()=> {}
  func2 : ()=> {}
  func3 : ()=> {}
}

then when you need a function, you can use the name of the function to access it in the function map

sourceFuncMap['func1']();
Aaron Saunders
  • 31,625
  • 5
  • 54
  • 74