Usage Guide

Using preact-layout requires you to:

  • Define contribution functions
  • Create a layout referncing these contribution functions
  • Make components that use the contribution functions
  • Learn about caveats

Define contribution functions

Define contribution functions to represent the different sections of your website / app:

function Header(){}
function Footer(){}

These functions's don't do anything in and of themselves, but they serve as symbols that can be used by both layouts and regular components.

Create a layout

Use Layout to create a layout which is subdivided in sections. Use Section to create those sections. There should be exactly one main section (not associated with a contribution function) and any children should be rendered inside this main section. In addition, layouts can have zero or more extra sections, each of which must be associated with a different contribution function, using the type attribute.

Have a look at this example:

function MyLayout({children}) {
    return (
        <Layout>
            <header>
                <Section type={Header}><h1>Default title</h1></Section>
            </header>

            <Section>{children}</Section>

            <footer>
                <Section type={Footer}><i>Default footer</i></Section>
            </footer>
        </Layout>
    )
}

Much simpler than it sounded right? But here's the cool trick: Any children of the main section will be rendered before the sections themselves and if they produce layout contributions, those contributions will be moved to the correct section based on the associated contribution function.

Make components that use the contribution functions

Again have a look at an example:

function HomePage({children}) {
    return (
        <div>
            <Header><h1>This is the homepage!</h1></Header>

            <p>And thats how preact-layout works. It takes the contributions made by the
            children and shows them in the correct region of the layout.</p>

            <Footer><p>Thank you for visiting!</p></Footer>
        </div>
    )
}

As you can see, in our components, we wrap the content that we want to contribute to other sections of the layout in JSX tags created from our contribution functions.

The magic happens when we combine the layout and the page we just created:

function Website({children, ...props}) {
    return (
        <MyLayout>
            <HomePage />
        </MyLayout>
    )
}

Website will render this output:

<div>
  <header>
        <h1>This is the homepage!</h1>
    </header>
    <div>
        <p>And thats how preact-layout works. It takes the contributions made by the
        children and shows them in the correct region of the layout.</p>
    </div>
    <footer>
        <p>Thank you for visiting!</p>
    </footer>
</div>

Because we separated the layout concerns from the HomePage component, we can easily make an alternative layout and use that instead:

function ReversedLayout({children}) {
    return (
        <Layout>
            <footer>
                <Section type={Footer}><i>Default footer</i></Section>
            </footer>

            <Section>{children}</Section>

            <header>
                <Section type={Header}><h1>Default title</h1></Section>
            </header>
        </Layout>
    )
}

Change Website to use the alternative layout and you're done:

function Website({children, ...props}) {
    return (
        <ReversedLayout>
            <HomePage />
        </ReversedLayout>
    )
}

The contributions made by HomePage will automatically land in the correct place:

<div>
    <footer>
        <p>Thank you for visiting!</p>
    </footer>
    <div>
        <p>And thats how preact-layout works. It takes the contributions made by the
        children and shows them in the correct region of the layout.</p>
    </div>
    <header>
        <h1>This is the homepage!</h1>
    </header>
</div>

Caveats

In the examples above we used stateless functional components. But preact-layout can be used with class components just as well:

class HomePage extends Component {
    render({children}) {return (
        <div>
            <Header><h1>This is the homepage!</h1></Header>

            <p>And thats how preact-layout works. It takes the contributions made by the
            children and shows them in the correct region of the layout.</p>

            <Footer><p>Thank you for visiting!</p></Footer>
        </div>
    )}
}

This works just as great. But things become a bit more tricky when we start using stateful class components. Consider this example:

class HomePage extends Component {
    state = {text: 'Hello, world!'};

    render({children}, {text}) {return (
        <div>
            <Header><h1>{text}</h1></Header>

            <p>This paragraph is in the main section</p>
            <input value={text} onInput={ this.linkState('text') } />

            <Footer><p>Thank you for visiting!</p></Footer>
        </div>
    )}
}

This will render fine and appears to work, until we change the text in the input. The changes will not be reflected in the header. The reason for this is that the children of the <Header> tag are actually moved outside of the HomePage component by the layout, so Preact does not re-render them in response to state changes.

The children of the HomePage that are not contributed to other sections will respond to state changes as expected. Also, you are free to

contribute stateful components. It's just that inside the component making the contributions, local state is not accessible in the contributed sections.

So either make components that contribute markup to the layout stateless, or take care to only make use of state in the main section of the component and not in those sections that are contributed to the layout.

The Preact Layout Kickstart CodePen actually demonstrates this.

results matching ""

    No results matching ""