From c541d7f33b4fe579d3010c91c0f0ca169bc4757d Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 14 Jan 2018 03:55:03 +0100 Subject: [PATCH 1/3] composable views --- content/docs/views/index.md | 66 +++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/content/docs/views/index.md b/content/docs/views/index.md index 65a79b4..ba80f0a 100644 --- a/content/docs/views/index.md +++ b/content/docs/views/index.md @@ -214,3 +214,69 @@ module.exports = function (state, emit) { showing the same title we already have, then we don't need to do anything. Conditional statements are less instructions on the CPU than function calls, so this provides us with a little speedup (and less noise). + +## Composable Views +As applications grow, you'll probably find that there will be plenty of views +that share a lot of the same layout. If you find that you're repeating the same +layout in a lot of code, it can be beneficial to make it reusable instead. + +The most common way to create reusable templates, is to create a function that +takes a view as an argument and returns a view. Inside the function the +childView is called, and wrapped with some HTML. The end result is a nicely +composed function that's also known as a "composable view", "higher order view", +"template". + +This might sound a little abstract. So let's create an example higher order +view, which has a static header and footer, but takes the content as an +argument. + +_note: There's not an exact word for what we're doing here. Because it's a +pattern, and not an API the exact word also doesn't matter too much. This is +also not at all the only way to compose functions - so don't worry too much +about getting the terminology right - we're also just making it up as we go._ + +```js +var html = require('choo/html') +var choo = require('choo') + +var app = choo() +app.route('/', template(main)) // 1. +app.route('/bar', template(bar)) // 2. +app.mount('body') + +function template (childView) { // 3. + return (state, emit) => { // 4. + return html` + +
This is the header
+ ${childView(state, emit)} + + + ` + } +} + +function main (state, emit) { // 5. + return html` +

I'm the main view

+ ` +} + +function foo (state, emit) { // 6. + return html` +

fooooooooooo view

+ ` +} +``` + +1. We create a route `'/'` which calls the `template` function, and passes it + the `main` view function. +2. We create a route `'/foo'` which calls the `template` function, and passes it + the `foo` view function. +3. This is where the bulk of the action happens. We create a function named + `'template'` which takes a view as an argument (`childView`). +4. The `'template'` function returns another function. This is the function + we'll be passing to `app.route()`. It's a valid view. When the view is + called, it calls the `childView`, and wraps it with DOM elements. +5. We define a view named `'main'`. +6. We define a view named `'foo'`. From 18544722f2a4380714fd89d931fffc439eca01e5 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 13 Mar 2018 13:47:39 +0100 Subject: [PATCH 2/3] include feedback --- content/docs/views/index.md | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/content/docs/views/index.md b/content/docs/views/index.md index ba80f0a..4236f9b 100644 --- a/content/docs/views/index.md +++ b/content/docs/views/index.md @@ -220,18 +220,18 @@ As applications grow, you'll probably find that there will be plenty of views that share a lot of the same layout. If you find that you're repeating the same layout in a lot of code, it can be beneficial to make it reusable instead. -The most common way to create reusable templates, is to create a function that +The most common way to create reusable templates is to create a function that takes a view as an argument and returns a view. Inside the function the childView is called, and wrapped with some HTML. The end result is a nicely composed function that's also known as a "composable view", "higher order view", -"template". +or "template". This might sound a little abstract. So let's create an example higher order view, which has a static header and footer, but takes the content as an argument. -_note: There's not an exact word for what we're doing here. Because it's a -pattern, and not an API the exact word also doesn't matter too much. This is +_note: There's not an exact term for what we're doing here. Because it's a +pattern, and not an API the exact term also doesn't matter too much. This is also not at all the only way to compose functions - so don't worry too much about getting the terminology right - we're also just making it up as we go._ @@ -240,12 +240,12 @@ var html = require('choo/html') var choo = require('choo') var app = choo() -app.route('/', template(main)) // 1. -app.route('/bar', template(bar)) // 2. +app.route('/', template(main)) +app.route('/bar', template(bar)) app.mount('body') -function template (childView) { // 3. - return (state, emit) => { // 4. +function template (childView) { // 1. + return (state, emit) => { // 2. return html`
This is the header
@@ -256,27 +256,21 @@ function template (childView) { // 3. } } -function main (state, emit) { // 5. +function main (state, emit) { return html`

I'm the main view

` } -function foo (state, emit) { // 6. +function foo (state, emit) { return html`

fooooooooooo view

` } ``` -1. We create a route `'/'` which calls the `template` function, and passes it - the `main` view function. -2. We create a route `'/foo'` which calls the `template` function, and passes it - the `foo` view function. -3. This is where the bulk of the action happens. We create a function named +1. This is where the bulk of the action happens. We create a function named `'template'` which takes a view as an argument (`childView`). -4. The `'template'` function returns another function. This is the function +2. The `'template'` function returns another function. This is the function we'll be passing to `app.route()`. It's a valid view. When the view is called, it calls the `childView`, and wraps it with DOM elements. -5. We define a view named `'main'`. -6. We define a view named `'foo'`. From b11a612b904e7d3097eea8f49ff78ef4af9d2509 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 13 Mar 2018 13:56:27 +0100 Subject: [PATCH 3/3] update snips --- content/docs/views/index.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/content/docs/views/index.md b/content/docs/views/index.md index 4236f9b..c04b025 100644 --- a/content/docs/views/index.md +++ b/content/docs/views/index.md @@ -220,6 +220,15 @@ As applications grow, you'll probably find that there will be plenty of views that share a lot of the same layout. If you find that you're repeating the same layout in a lot of code, it can be beneficial to make it reusable instead. +The easiest way to create a reusable view in Choo is to create a function that +takes a view (meaning a snippet of HTML) and then inserts it into another, +internal view. This makes it easy to create functions that construct HTML that +you always want to keep static, such as a menu bar. But at the same time +construct dynamic HTML defined by whatever you pass it as an argument. + +Functions like these are called "composable functions" and coincidentally happen +to be a fundamental piece of functional programming! + The most common way to create reusable templates is to create a function that takes a view as an argument and returns a view. Inside the function the childView is called, and wrapped with some HTML. The end result is a nicely