TheSpicyMeatball / react-nanny

Utils to manage your React Children
Other
85 stars 4 forks source link

How to set props of deeply searched nodes? #7

Closed furkanorhan23 closed 3 years ago

furkanorhan23 commented 3 years ago

I planned to use this library for a compound tabs component implementation.

My intention was to detect Tab or TabPanel components that are children of Tabs wrapper component. I was hoping that I was going to be able to search components with types and then just override props.

Although this library helps me find specified typed components, that exists deeply and not being direct children of a shared wrapper node, it doesn't let me just override props. The task of replacing those nodes is still my responsibility.

Do you have any suggestion on how to override those searched components props?

overridePropsDeep(getChildrenByTypeDeep(children, Tab), () => ({ active: true }))

Screen Shot 2021-08-14 at 17 47 22

Thanks for this library and your great article.

TheSpicyMeatball commented 3 years ago

@furkanorhan23

If I understand you correctly, you want to update the props of all of your deeply nested Tab children but still maintain your original children structure?

The code that you posted there will set all Tab children to active, but you'll get an array of all of those children instead of your original structure. If I'm misunderstanding you, please disregard what I'm about to say.

I think what you'll want do is sometime like this...

overridePropsDeep(children, child => typeOfComponent(child) === 'Tab' ? { active: true } : {});

When the overridePropsDeep iterates over each child, it will send that child as an argument to the childOverrides function. From there you can check the type and set the prop how you'd like based on that condition.

Here is the README.md for typeOfComponent... https://github.com/TheSpicyMeatball/react-nanny/blob/main/src/typeOfComponent/README.md

I hope this helps. If I'm misunderstanding you, please let me know!

furkanorhan23 commented 3 years ago

Thanks for your answer.

So if I got you, I need to map my direct children and when I overridePropsDeep any child mapped, they will deeply get updated and so that I will accomplish my unnested/deeply prop overriding task.

If that is true, great! I will test this case soon.

TheSpicyMeatball commented 3 years ago

overridePropsDeep will internally iterate over all of your children (deeply) and the function that you pass in will be invoked with each iteration. Inside that function, you decide if this is a component whose props you want to override. In your case, you want to update all of the Tab components so you'll check for the typeOfComponent to ensure it's a Tab. If you don't want to override any props, in your case because it's not a Tab, return an empty object.

Whatever object your function returns will be spread onto the props object. That is why you'll want to return an empty one if you don't want to override anything.

charleshimmer commented 2 years ago

I am trying to use overridePropsDeep to do this very thing, and am finding it will override any prop I set except the children prop. Is that one safe guarded or something?

Here is what I'm doing:

 const modified = overridePropsDeep(this._content, (child) => {
  if (typeOfComponent(child) === 'SearchableText') {
    return { children: ['ha!', 'foo'], active: true };
  }
  return {};
});

console.log('modified', modified);

You can see the console output below, the active prop was correctly modified, but the children prop was left untouched.

image

charleshimmer commented 2 years ago

@TheSpicyMeatball curious if you would see my comment above given this is a closed issue. I can open a new issue if that makes more sense.

charleshimmer commented 2 years ago

For anyone else who stumbles upon this, React treats the children prop as special and you can't override it using the second argument of the React.cloneElement function. You have to use the third argument to override the children prop. I ended up writing my own function to do this for the cases I needed.

image