0

I need some ideas for a folder structure/mental model in React.

I have an Item component. It stays the same. It can be wrapped in either a Link with a URL prop or a Button with an onClick prop.

My current folder structure solution looks like this:

-Item
  -wrapperComponents
    -Link
    -Button

Both the Link and Button components wrap around the children prop. Much like this:

react stuff ...

return(
  <button onClick={props.handleOnClick}>
    {props.children}
  </button>
)

And this is how I call them:

<Button>
  <Item />
</Button>

or

<Link>
  <Item />
</Link>

I am looking for a better, more elegant solution.

I've tried sending the wrapper components to the Item but React doesn't allow to use them as a wrapper that would take children.

Des
  • 213
  • 1
  • 3
  • 14
  • Are you looking at improving the way you call them? What would look elegant to you? – Antoine Trouve Aug 04 '22 at 06:58
  • so i think this is what you are looking for https://www.smashingmagazine.com/2021/08/compound-components-react/ – Talha Fayyaz Aug 04 '22 at 07:34
  • @TalhaFayyaz I am looking for the reverse logic of a Compound Component. While with Compound Components you call the parent and their nested children, I need a way to only call the child and from it to choose a parent. – Des Aug 04 '22 at 08:07
  • in that case what you can do is something like passing the Wrapper Component as Prop and using it like this: your item component – Talha Fayyaz Aug 04 '22 at 08:13
  • @TalhaFayyaz sadly this doesn't work. As I mentioned in the post sending the Wrapper component in the props and wrapping it around the child crashes React. I can send a component that doesn't wrap around without any issues but one that wraps around and displays children breaks React. – Des Aug 04 '22 at 08:46
  • can you please send that specific component I can help you fix it. – Talha Fayyaz Aug 04 '22 at 08:49
  • @TalhaFayyaz I don't have it. I've scrapped the work yesterday. I've tried to use the solution from over here https://stackoverflow.com/questions/41299203/pass-a-wrapper-component-as-props-in-reactjs but it doesn't work. React crashes. – Des Aug 04 '22 at 08:52
  • Ha! Strange thing is, I tried to replicate the problem to show you the issue and it works. https://codesandbox.io/s/create-react-app-forked-wlmkyv?file=/src/components/Item.jsx I'll try to solve this in a future reference. Thank you for the help :) – Des Aug 04 '22 at 09:06

2 Answers2

0

This is what you can do:

import "./styles.css";
import Item from "./Item";
import Wrapper1 from "./Wrapper1";

export default function App() {
  return (
    <div className="App">
      <Item wrapper={Wrapper1} />
    </div>
  );
}

Item component:

const Item = ({ wrapper: Wrapper }) => {
  return (
    <Wrapper>
      <div>This is my child</div>
    </Wrapper>
  );
};

export default Item;

Wrapper component:

const Wrapper1 = ({ children }) => {
  return (
    <div>
      This is my wrapper
      {children}
    </div>
  );
};

export default Wrapper1;

https://codesandbox.io/s/quirky-vaughan-4op2l1?file=/src/index.js

Talha Fayyaz
  • 481
  • 2
  • 9
  • Thank you for the answer. I've added one that handles the props too. I'm really happy when the community comes up with solutions together. – Des Aug 04 '22 at 10:25
0

I've come up with this solution with the help you you guys

https://codesandbox.io/s/create-react-app-forked-wlmkyv?file=/src/App.js

Main component App.js:

import * as React from "react";
import Wrapper from "./components/Wrapper";
import Item from "./components/Item";

function App() {
  return (
    <div>
      <Item wrapper={Wrapper} wrapperProps={{ color: "orange" }} />
    </div>
  );
}

export default App;

Item component Item.js:

import * as React from "react";

function Item(props) {
  const Wrapper = props.wrapper;
  const wrapperProps = props.wrapperProps;

  return (
    <Wrapper {...wrapperProps}>
      <div>An Item</div>
    </Wrapper>
  );
}

export default Item;

Wrapper component Wrapper.js:

import * as React from "react";

function Wrapper(props) {
  return (
    <div style={{ backgroundColor: props.color || "red" }}>
      {props.children}
    </div>
  );
}

export default Wrapper;
Des
  • 213
  • 1
  • 3
  • 14