Reputation: 408
I have a React component that works 'standalone'. It allows child components to be editable (dynamically) with an 'editable' state (editable = true
makes children editable, editable = false
does not)
import Editable from './editable'
<Editable>
<div>edit me!</div>
</Editable>
Next to this component I have some 'sub components' that could be used as children for the 'main component' (Editable
). The can be used to specify other behavior for their children, when Editable
's state is set to 'editable = true'. I don't want to import these sub components all separately. I know some ways to achieve this, I will specify them below the question.
But what I'm looking for is syntax like this:
import Editable from './editable'
<Editable>
<div>edit me!</div>
<Editable.Hide>
<div>don't show me when editable</div>
</Editable.Hide>
<Editable.Not>
<div>don't make me editable when editable</div>
</Editable.Not>
</Editable>
So the export needs to be structured so that the usage of the default export will result in the main component, but (somehow) the sub components can also be accessed through that same default export.
Why? Mostly my curiosity into the possibilities and I would love to use a syntax like the above.
So is it possible to structure an export to be able to use a syntax like that?
These are the ways I already know how to import components with sub components:
import Editable from './editable'
<Editable.MainComponent>
<div>edit me!</div>
<Editable.Hide>
<div>don't show me when editable</div>
</Editable.Hide>
<Editable.Not>
<div>don't make me editable when editable</div>
</Editable.Not>
</Editable.MainComponent>
If I would only want the main components, I could do this with some filestructure in the editable
folder and import like this:
import EditableMainComponent from './editable/mainComponent'
<EditableMainComponent>
<div>edit me!</div>
</EditableMainComponent>
Or create a named export with only the main component in the same file.
import {EditableMainComponent} from './editable'
<EditableMainComponent>
<div>edit me!</div>
</EditableMainComponent>
Another way to go is to keep only the main component as the default export and the sub components as named exports.
I am trying to avoid usage like this:
import Editable, {EditableHide, EditableNot} from './editable'
<Editable>
<div>edit me!</div>
<EditableHide>
<div>don't show me when editable</div>
</EditableHide>
<EditableNot>
<div>don't make me editable when editable</div>
</EditableNot>
</Editable>
Because I don't want the user to have to specify all the different sub components in the import. So that could also be achieved like this:
import { * as Editable } from './editable'
<Editable.default>
<div>edit me!</div>
<Editable.Hide>
<div>don't show me when editable</div>
</Editable.Hide>
<Editable.Not>
<div>Don't make me editable when editable</div>
</Editable.Not>
</Editable.default>
Upvotes: 0
Views: 491
Reputation: 222369
If components are self-sufficient and can be used separately, it's preferable to consider them of the same value and treat all of them as named exports:
import {Editable, EditableHide, EditableNot} from './editable'
If some components aren't supposed to be used apart from main component, they can be namespaced with it.
For class components:
class Not extends Component {...}
export default class Editable extends Component {
static Not = Not;
...
}
For functional components:
const Not = props => ...;
const Editable = props => ...;
Editable.Not = Not;
export default Editable;
The advantage of the last approach is that this improves testability by mocking or spying secondary components in tests, as long as they are referred as Editable.Not
and not Not
inside Editable
main component.
The disadvantage of the last approach is that secondary components cannot be tree-shaken, this shouldn't be done in case their footprint is large and main component can be often used without them.
Upvotes: 2