Créez des composants de mise en page flexibles et d'interface utilisateur composite sans avoir besoin de définir des accessoires personnalisés arbitraires.
npm i macro-components
import React from 'react'
import styled from 'styled-components'
import Macro from 'macro-components'
import { space , fontSize , color } from 'styled-system'
// Define some styled-components
const Box = styled . div ` ${ space } ${ fontSize } ${ color } `
Box . displayName = 'Box'
const Image = styled . img `
max-width: 100%;
height: auto;
${ space }
`
Image . displayName = 'Image'
const Heading = styled . h2 ` ${ space } ${ fontSize } ${ color } `
Heading . displayName = 'Heading'
const Text = styled . div ` ${ space } ${ fontSize } ${ color } `
Text . displayName = 'Text'
// create a macro function with the UI components you intend to use
const macro = Macro ( {
Image ,
Heading ,
Text
} )
// Create a macro-component
const MediaObject = macro ( ( {
Image ,
Heading ,
Text
} ) => (
< Flex p = { 2 } align = 'center' >
< Box width = { 128 } >
{ Image }
</ Box >
< Box >
{ Heading }
{ Text }
</ Box >
</ Flex >
) ) import MediaObject from './MediaObject'
// get the macro component's child components
const { Image , Heading , Text } = MediaObject
// Use the macro-component by passing the components as children
const App = props => (
< div >
< MediaObject >
< Image src = 'kitten.png' />
< Heading >
Hello
</ Heading >
< Text >
This component keeps its tree structure but still allows for regular composition.
</ Text >
</ MediaObject >
</ div >
) Remarque: les composants macro sont destinés à ne travailler qu'avec des composants enfants spécifiques. Si vous souhaitez définir des créneaux , consultez la section des alternatives ci-dessous.
Souvent, il est préférable d'utiliser la composition et props.children React.Children pour créer une interface utilisateur composée de plusieurs éléments, mais parfois vous voudrez peut-être créer des composants composites plus grands avec des structures d'arbres encapsulées pour la mise en page ou créer des composants d'interface utilisateur de type bootstrap tels que des panneaux, des cartes ou des alertes. Cette bibliothèque vous permet de créer des composants composites avec des structures DOM encapsulées sans avoir besoin de définir des API accessoires arbitraires et qui fonctionnent comme n'importe quelle autre composition React.
Cela peut aider à garantir que la surface de votre composante API reste petite et plus facile à entretenir.
Si vous vous retrouvez à créer des composants React Composite qui ne mappent pas aux structures de données, comme décrit dans Thinking in React, alors ce module vous est destiné.
Macro(componentsObject)(elementFunction)
Renvoie un composant React avec une API composable qui maintient la structure de disposition des arbres.
const Banner = Macro ( {
// pass a components object
Heading ,
Subhead
} ) ( ( {
// the element function receives child elements
// named according to the components object
Heading ,
Subhead
} ) => (
< Box p = { 3 } color = 'white' bg = 'blue' >
{ Heading }
{ Subhead }
</ Box >
) L'argument elementFunction est appelé avec un objet d'éléments basé sur les componentsObject transmis à la fonction macro. L'utilisation du composant de bannière ci-dessus ressemblerait à ce qui suit.
import Banner from './Banner'
const App = ( ) => (
< Banner >
< Banner . Heading > Hello </ Banner . Heading >
< Banner . Subhead > Subhead </ Banner . Subhead >
</ Banner >
)L'objet composants est utilisé pour définir les composants que le composant macro acceptera comme enfants.
La fonction d'élément est similaire à un composant React, mais reçoit un objet Elements comme premier argument et accessoires comme deuxième. L'objet Elements est créé à partir de ses enfants et est destiné à faciliter la composition et les structures d'éléments d'encapsulation.
Dans le composant macro, la fonction d'élément est appelée avec l'objet Elements et les accessoires: elementFunction(elementsObject, props) .
// example
const elFunc = ( { Heading , Text , } , props ) => (
< header >
{ Heading }
{ Text }
</ header >
)
const Heading = styled . h2 ``
const Text = styled . div ``
const componentsObj = {
Heading ,
Text
}
const SectionHeader = Macro ( componentsObj ) ( elFunc ) Pour tout élément non transmis en tant qu'enfant au composant macro, la fonction d'élément rendra undefined et réagira ne rendra pas cet élément. Ceci est utile pour omettre conditionnellement les enfants optionnels
const macro = Macro ( { Icon , Text , CloseButton } )
const Message = macro ( {
Icon ,
Text ,
CloseButton
} ) = > (
< Flex p = { 2 } bg = 'lightYellow' >
{ Icon }
{ Text }
< Box mx = 'auto' />
{ CloseButton }
</ Flex >
) import Message from './Message'
const { Text , CloseButton } = Message
// Omitting the Icon child element will render Message without an icon.
const message = (
< Message >
< Text > { props . message } </ Text >
< CloseButton
onClick = { props . dismissMessage }
/>
</ Message >
)Le deuxième argument transmis à la fonction d'élément vous permet de transmettre des accessoires à l'élément racine ou à tout autre élément dans le composant.
const macro = Macro ( { Image , Text } )
const Card = macro ( ( {
Image ,
Text
} , props ) => (
< Box p = { 2 } bg = { props . bg } >
{ Image }
{ Text }
</ Box >
) ) // example usage
< Card bg = 'tomato' >
< Card . Image src = 'kittens.png' />
< Card . Text > Meow </ Card . Text >
</ Card >Pour appliquer des accessoires par défaut aux éléments transmis en tant qu'enfants, utilisez le composant de clone dans une fonction d'élément.
import Macro , { Clone } from 'macro-components'
import { Heading , Text } from './ui'
const macro = Macro ( { Heading , Text } )
const Header = macro ( ( { Heading , Text } ) => (
< Box p = { 2 } >
< Clone
element = { Heading }
fontSize = { 6 }
mb = { 2 }
/>
< Clone
element = { Text }
fontSize = { 3 }
/>
</ Box >
) )Pour utiliser deux fois le même composant, donnez-lui une clé unique dans les composants Object.
import React from 'react'
import Macro from 'macro-components'
import { Heading } from './ui'
const macro = Macro ( {
Heading : Heading ,
Subhead : Heading
} )
const Header = macro ( ( { Heading , Subhead } ) => (
< Box p = { 2 } >
{ Heading }
{ Subhead }
</ Box >
) ) < Header >
< Header . Heading > Hello </ Header . Heading >
< Header . Subhead > Subhead </ Header . Subhead >
</ Header >Pour créer des composants de mise en page qui ne sont pas couplés à des composants enfants spécifiques, l'utilisation d'accessoires ou d'enfants ordonnés est probablement une approche plus simple.
Les solutions ci-dessous vous permettent de passer les composants arbitraires en tant qu'accessoires ou enfants.
Voir cette discussion pour en savoir plus.
// using custom props
const MyLayout = ( {
left ,
right
} ) => (
< Flex >
< Box width = { 128 } >
{ left }
</ Box >
< Box width = { 1 } >
{ right }
</ Box >
</ Flex >
)
< MyLayout
left = { (
< Image src = 'kitten.png' />
) }
right = { (
< Text > Meow </ Text >
) }
/ > // using ordered children
const Header = props => {
const [ first , second ] = React . Children . toArray ( props . children )
return (
< Box p = { 3 } >
{ first }
{ second }
</ Box >
)
}
< Header >
< Heading > First </ Heading >
< Text > Second < / Text>
</ Header > // using a children object
const Header = ( {
children : {
left ,
right
}
} ) => (
< Flex >
< Box >
{ left }
</ Box >
< Box width = { 1 } >
{ right }
</ Box >
</ Flex >
)
< Header >
{ {
left : (
< Image src = 'kitten.png' />
) ,
right : (
< Text > Meow </ Text >
)
} }
</ Header > Licence MIT