Asking
Asking

Reputation: 4200

Create a component as a children of another in React.Js

I create a component which is a parent component of another: Container is parent and Container.Data children. In this way I can add a structure to my component.

const Container = ({ children }) => {
  return (
    <div>
      <h1>Container</h1>
      {children}
    </div>
  );
};

const Data = ({ children }) => {
  return <div>{children}</div>;
};

Container.Data = Data;

export { Container };


///

  <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Container>
        <Container.Data>item1</Container.Data>
        <Container.Data>item2</Container.Data>
      </Container>
      <Container.Data>item3</Container.Data>
  </div>

The issue is next: <Container.Data>item3</Container.Data> is outside the component and it works, but I want in the case when I will add the <Container.Data>item3</Container.Data> outside the parent Container, to get an error. So all items should be only inside Container.
Question: How to do this?
demo: https://codesandbox.io/s/stupefied-dubinsky-6lh8v?file=/src/Container.js:27-264

Upvotes: 1

Views: 352

Answers (3)

Swaraj Gandhi
Swaraj Gandhi

Reputation: 714

You can pass the extra param in children of container and check in Data component that if that component has the prop or not. If it does not then ignore the child.

import React from "react";

const Container = ({ children }) => {
  return (
    <div className="parent-container">
      <h1>Container</h1>
      {React.Children.map(children, (child, i) => {
        return React.cloneElement(child, {
          fromParent: true
        });
      })}
    </div>
  );
};

const Data = ({ children, fromParent }) => {
  if (!fromParent) {
    return null;
  }
  return <div>{children}</div>;
};

Container.Data = Data;

export { Container };

https://codesandbox.io/s/naughty-elion-42ppn?file=/src/Container.js:0-474

Upvotes: 1

Drew Reese
Drew Reese

Reputation: 203532

Use a React Context to create a context for the Data component to "check-in" with. Provide a defaultValue to the context that is overridden by a "real" value by the provider. If a component subscribed to the context doesn't have a matching Provider above it in the tree it uses this default value.

import React from "react";

const ContainerContext = React.createContext("containerless");

const Container = ({ children }) => {
  return (
    <ContainerContext.Provider value="Container">
      <div>
        <h1>Container</h1>
        {children}
      </div>
    </ContainerContext.Provider>
  );
};

const Data = ({ children }) => {
  const containerContext = React.useContext(ContainerContext);

  React.useEffect(() => {
    if (containerContext === "containerless") {
      throw new Error("Data Container not contained in Container component");
    }
  });
  return <div>{children}</div>;
};

Container.Data = Data;

export { Container };

Edit create-a-component-as-a-children-of-another-in-react-js

App

Move the "item3" data container in and out of Container to test.

function App() {
  return (
    <div className="App">
      <Container>
        <Container.Data>item1</Container.Data>
        <Container.Data>item2</Container.Data>
      </Container>
      <Container.Data>item3</Container.Data>
    </div>
  );
}

Upvotes: 2

Armando Guarino
Armando Guarino

Reputation: 1631

In order to achieve better readability, I would suggest having each element structured in different files and then importing them when needed like so:

import Container from './Container';

Then you'll be able to use them in your App file without problems.

Upvotes: 0

Related Questions