### Counter Component Example (Elm)
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Illustrates a stateful counter component in Elm, following the Elm Architecture. It defines separate initial model, transition function, and view calculations, and shows how to use Browser.sandbox for application setup.
```Elm
module Main exposing (main)
import Browser
import Counter
update =
Counter.update 1
view =
Counter.view 1 "counter"
main =
Browser.sandbox { init = Counter.init, update = update, view = view }
```
--------------------------------
### Counter Component Example (Bonsai)
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Demonstrates a stateful counter component using Bonsai's state_machine1 primitive. It shows how to create a component that yields both a view and a counter value, and how to integrate it into an application.
```Bonsai
open! Core
open! Import
let app graph =
let view, _ = Counter.component ~label:(Bonsai.return "counter") graph in
view
;;
let () = Start.start app
```
--------------------------------
### Parallel Composition Example (Bonsai)
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Demonstrates parallel composition of isolated components in Bonsai. Two independent counter components are created and arranged side-by-side within a container.
```Bonsai
open! Core
open! Import
let app graph =
let first, _ = Counter.component ~label:(Bonsai.return "first") graph in
let second, _ = Counter.component ~label:(Bonsai.return "second") graph in
let%map first and second in
N.div [ first; second ]
;;
let () = Start.start app
```
--------------------------------
### Bonsai Parallel Composition Example
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
This OCaml code demonstrates parallel composition using Bonsai. It creates two independent Counter components and composes their views.
```ocaml
open! Core
open! Import
let app graph =
let first, _ = Counter.component ~label:(Bonsai.return "first") graph in
let second, _ = Counter.component ~label:(Bonsai.return "second") graph in
let%map first and second in
N.div [ first; second ]
;;
let () = Start.start app
```
--------------------------------
### Parallel Composition Example (Elm)
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Shows parallel composition of components in Elm. This snippet sets up the structure for composing multiple independent components, though the specific rendering of the second component is omitted in the provided text.
```Elm
module Main exposing (main)
import Browser
import Counter
```
--------------------------------
### Elm Parallel Composition Example
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
This Elm code showcases parallel composition by creating two Counter components. It defines the necessary Model, Msg, init, update, and view functions to manage and render these components.
```elm
module Main exposing (main)
import Browser
import Counter
import Html exposing (Html, div)
type alias Model =
{ first : Counter.Model, second : Counter.Model }
init : Model
init =
{ first = Counter.init, second = Counter.init }
type Msg
= First Counter.Msg
| Second Counter.Msg
update : Msg -> Model -> Model
update msg model =
case msg of
First msg_first ->
{ model | first = Counter.update 1 msg_first model.first }
Second msg_second ->
{ model | second = Counter.update 1 msg_second model.second }
view : Model -> Html Msg
view model =
div []
[ Html.map First (Counter.view 1 "first" model.first)
, Html.map Second (Counter.view 1 "second" model.second)
]
main =
Browser.sandbox { init = init, update = update, view = view }
```
--------------------------------
### Counter Component Example (React)
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Presents a stateful counter component in React using the `useReducer` hook for state management. It shows how to pass state and dispatch functions down to a child `Counter` component and render it using ReactDOM.
```React
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';
import Counter, { applyAction, defaultState } from '../../shared/Counter';
const App = () => {
let [state, inject] = useReducer(
(state, action) => applyAction(state, action, 1),
defaultState
);
return ;
};
ReactDOM.render(, document.getElementById('app'));
```
--------------------------------
### Elm Sequential Composition Example
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Illustrates sequential composition in Elm, where the state of the 'how many' counter dictates the number of other counter components rendered. The second counter's update logic depends on the model of the first component.
```elm
open! Core
open! Import
let app graph =
let counter_view, how_many = Counter.component ~label:(Bonsai.return "how many") graph in
let map =
let%map how_many in
List.init how_many ~f:(fun i -> i, ()) |> Int.Map.of_alist_exn
in
let others = Bonsai.assoc (module Int) map graph ~f:(fun key _data graph ->
let view, _ = Counter.component ~label:(key >>| Int.to_string) graph in
view)
in
let%map counter_view and others in
N.div (counter_view :: Map.data others)
;;
let () = Start.start app
```
```elm
module Main exposing (main)
import Browser
import Counter
import Dict exposing (Dict)
import Html exposing (Html, div, map)
type alias Model =
{ howMany : Counter.Model, others : Dict Int Counter.Model }
init : Model
init =
{ howMany = Counter.init, others = Dict.empty }
type Msg
= HowMany Counter.Msg
| ForKey Int Counter.Msg
updateOther which msg =
Dict.update which
(\m ->
Just (Counter.update 1 msg (Maybe.withDefault 0 m))
)
update : Msg -> Model -> Model
update appMsg model =
case appMsg of
HowMany msgHowMany ->
{ model | howMany = Counter.update 1 msgHowMany model.howMany }
ForKey which msg ->
{ model | others = updateOther which msg model.others }
viewOther : Dict Int Counter.Model -> Int -> Html Counter.Msg
viewOther models key =
case Dict.get key models of
Just model ->
Counter.view 1 (String.fromInt key) model
Nothing ->
Counter.view 1 (String.fromInt key) Counter.init
view : Model -> Html Msg
view model =
List.range 0 (model.howMany - 1)
|> List.map (i -> Html.map (ForKey i) (viewOther model.others i))
|> List.append [ Html.map HowMany (Counter.view 1 "how many" model.howMany) ]
|> div []
main =
Browser.sandbox { init = init, update = update, view = view }
```
--------------------------------
### React Sequential Composition Example
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Demonstrates sequential composition in React using `useReducer`. The state of one counter component influences the update logic of another, showcasing how to handle inter-component dependencies within a single reducer.
```javascript
case 'first':
return {
...state,
first: counterApplyAction(state.first, subAction, 1),
};
case 'second':
return {
...state,
second: counterApplyAction(state.second, subAction, state.first),
};
}
}
const App = () => {
let [state, inject] = useReducer(applyAction, defaultState);
let injectFirst = (subAction) => inject({ which: 'first', subAction });
let injectSecond = (subAction) => inject({ which: 'second', subAction });
return (
);
};
ReactDOM.render(, document.getElementById('app'));
```
--------------------------------
### React Parallel Composition Example
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
This React (JSX) code demonstrates parallel composition by rendering two independent Counter components. It uses the `useReducer` hook to manage the state for each counter.
```jsx
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';
import Counter, { applyAction, defaultState } from '../../shared/Counter';
const App = () => {
let [state1, inject1] = useReducer(
(state, action) => applyAction(state, action, 1),
defaultState
);
let [state2, inject2] = useReducer(
(state, action) => applyAction(state, action, 1),
defaultState
);
return (
);
};
ReactDOM.render(, document.getElementById('app'));
```
--------------------------------
### Bonsai Counter Component Usage
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
Demonstrates how to use a Bonsai counter component, passing a label and utilizing the default 'by' value.
```ocaml
open! Core
open! Import
let app graph =
let view, _ = Counter.component ~label:(Bonsai.return "counter") graph in
view
;;
let () = Start.start app
```
--------------------------------
### Elm Counter Component Usage
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
Shows the Elm approach to using a counter component, configuring it with an initial value and a label, and integrating it into a browser sandbox.
```elm
module Main exposing (main)
import Browser
import Counter
update =
Counter.update 1
view =
Counter.view 1 "counter"
main =
Browser.sandbox { init = Counter.init, update = update, view = view }
```
--------------------------------
### Bonsai Parallel Composition
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Shows parallel composition in Bonsai. It defines an `app` graph that instantiates two `Counter.component`s in parallel.
```Bonsai
open! Core
open! Import
let app graph =
let first_view, by = Counter.component ~label:(Bonsai.return "first") graph in
let second_view, _ = Counter.component ~label:(Bonsai.return "second") ~by graph in
let%map first = first_view
and second = second_view in
N.div [ first; second ]
;;
let () = Start.start app
```
--------------------------------
### Bonsai Counter Component (OCaml)
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Defines a configurable counter component using the Bonsai framework. It handles state management for incrementing/decrementing a value and accepts a label and a delta value for configuration. The component exposes its view and state.
```OCaml
open! Core
open! Import
let apply_action _ctx by model = function
| `Incr -> model + by
| `Decr -> model - by
;;
let component ~label ?(by = Bonsai.return 1) graph =
let state, inject = Bonsai.state_machine1 ~default_model:0 ~apply_action by graph in
let view =
let%map state and inject and by and label in
let button op action =
N.button ~attr:(A.on_click (fun _ -> inject action)) [ N.textf "%s%d" op by ]
in
N.div
[ Vdom.Node.span [ N.textf "%s: " label ]
; button "-" Decr
; Vdom.Node.span [ N.textf "%d" state ]
; button "+" Incr
]
in
view, state
;;
```
--------------------------------
### Bonsai Counter Component (OCaml)
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
Defines a stateful counter component using Bonsai. It supports a configurable label and increment/decrement delta. The component exposes both its view and its current state.
```ocaml
open! Core
open! Import
let apply_action _ctx by model = function
| `Incr -> model + by
| `Decr -> model - by
;;
let component ~label ?(by = Bonsai.return 1) graph =
let state, inject = Bonsai.state_machine1 ~default_model:0 ~apply_action by graph in
let view =
let%map state and inject and by and label in
let button op action =
N.button ~attr:(A.on_click (fun _ -> inject action)) [ N.textf "%s%d" op by ]
in
N.div
[ Vdom.Node.span [ N.textf "%s: " label ]
; button "-" Decr
; Vdom.Node.span [ N.textf "%d" state ]
; button "+" Incr
]
in
view, state
;;
```
--------------------------------
### Basic CSS Styling
Source: https://github.com/tyoverby/composition-comparison/blob/main/03-sequential/bonsai-2023/index.html
Applies basic padding and margin resets to the main body element.
```css
body {
padding: 0;
margin: 0;
}
```
--------------------------------
### Bonsai 2023 Dynamic Counter Component
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
This OCaml code uses Bonsai to dynamically render multiple counter components based on the value of a 'how many' counter. It utilizes Bonsai.assoc to manage the creation and rendering of these dynamic subcomponents.
```ocaml
open! Core
open! Import
let app graph =
let counter_view, how_many = Counter.component ~label:(Bonsai.return "how many") graph in
let map =
let%map how_many in
List.init how_many ~f:(fun i -> i, ()) |> Int.Map.of_alist_exn
in
let others = Bonsai.assoc (module Int) map graph ~f:(fun key _data graph ->
let view, _ = Counter.component ~label:(key >>| Int.to_string) graph in
view)
in
let%map counter_view and others in
N.div (counter_view :: Map.data others)
;;
let () = Start.start app
```
--------------------------------
### Elm Sequential Composition
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
Elm code demonstrating sequential composition by passing the first counter's model to the second counter's update and view functions.
```elm
module Main exposing (main)
import Browser
import Counter
import Html exposing (Html, div)
type alias Model =
{ first : Counter.Model, second : Counter.Model }
init : Model
init =
{ first = Counter.init, second = Counter.init }
type Msg
= First Counter.Msg
| Second Counter.Msg
update : Msg -> Model -> Model
update msg model =
case msg of
First msg_first ->
{ model | first = Counter.update 1 msg_first model.first }
Second msg_second ->
{ model | second = Counter.update model.first msg_second model.second }
view : Model -> Html Msg
view model =
div []
[ Counter.view 1 "first" model.first |> Html.map First
, Counter.view model.first "second" model.second |> Html.map Second
]
main =
Browser.sandbox { init = init, update = update, view = view }
```
--------------------------------
### Elm Sequential Composition
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Demonstrates sequential composition in Elm, where the state of one counter influences the other. The `update` function and `view` logic are adjusted accordingly.
```Elm
module Main exposing (main)
import Browser
import Counter
import Html exposing (Html, div)
type alias Model =
{ first : Counter.Model, second : Counter.Model }
init : Model
init =
{ first = Counter.init, second = Counter.init }
type Msg
= First Counter.Msg
| Second Counter.Msg
update : Msg -> Model -> Model
update msg model =
case msg of
First msg_first ->
{ model | first = Counter.update 1 msg_first model.first }
Second msg_second ->
{ model | second = Counter.update model.first msg_second model.second }
view : Model -> Html Msg
view model =
div []
[ Counter.view 1 "first" model.first |> Html.map First
, Counter.view model.first "second" model.second |> Html.map Second
]
main =
Browser.sandbox { init = init, update = update, view = view }
```
--------------------------------
### CSS Main Body Styling
Source: https://github.com/tyoverby/composition-comparison/blob/main/01-basic/bonsai/index.html
Applies zero padding and margin to the main body element for consistent layout.
```CSS
Main body {
padding: 0;
margin: 0;
}
```
--------------------------------
### CSS Main Body Styling
Source: https://github.com/tyoverby/composition-comparison/blob/main/02-parallel/bonsai/index.html
Applies zero padding and margin to the main body element for consistent layout.
```CSS
Main body {
padding: 0;
margin: 0;
}
```
--------------------------------
### CSS Main Body Styling
Source: https://github.com/tyoverby/composition-comparison/blob/main/03-sequential/bonsai/index.html
Applies zero padding and margin to the main body element for consistent layout.
```CSS
Main body {
padding: 0;
margin: 0;
}
```
--------------------------------
### Bonsai 2023 Sequential Composition
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
OCaml code using Bonsai to compose two counter components sequentially. The state of the first counter influences the second.
```ocaml
open! Core
open! Import
let app graph =
let first_view, by = Counter.component ~label:(Bonsai.return "first") graph in
let second_view, _ = Counter.component ~label:(Bonsai.return "second") ~by graph in
let%map first = first_view
and second = second_view in
N.div [ first; second ]
;;
let () = Start.start app
```
--------------------------------
### Elm Parallel Composition
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Demonstrates parallel composition in Elm. It sets up two independent counter components and maps their messages to a parent message type.
```Elm
import Html exposing (Html, div)
type alias Model =
{ first : Counter.Model, second : Counter.Model }
init : Model
init =
{ first = Counter.init, second = Counter.init }
type Msg
= First Counter.Msg
| Second Counter.Msg
update : Msg -> Model -> Model
update msg model =
case msg of
First msg_first ->
{ model | first = Counter.update 1 msg_first model.first }
Second msg_second ->
{ model | second = Counter.update 1 msg_second model.second }
view : Model -> Html Msg
view model =
div []
[ Html.map First (Counter.view 1 "first" model.first)
, Html.map Second (Counter.view 1 "second" model.second)
]
main =
Browser.sandbox { init = init, update = update, view = view }
```
--------------------------------
### CSS Main Body Styling
Source: https://github.com/tyoverby/composition-comparison/blob/main/04-multiplicity/bonsai/index.html
Applies zero padding and margin to the main body element for consistent layout.
```CSS
Main body {
padding: 0;
margin: 0;
}
```
--------------------------------
### CSS Main Body Styling
Source: https://github.com/tyoverby/composition-comparison/blob/main/01-basic/bonsai-2023/index.html
Applies zero padding and margin to the main body element for consistent layout.
```CSS
Main body {
padding: 0;
margin: 0;
}
```
--------------------------------
### CSS Main Body Styling
Source: https://github.com/tyoverby/composition-comparison/blob/main/02-parallel/bonsai-2023/index.html
Applies zero padding and margin to the main body element for consistent layout.
```CSS
Main body {
padding: 0;
margin: 0;
}
```
--------------------------------
### CSS Styling for Document Elements
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
This snippet defines general CSS styles for HTML elements such as html, body, headings, lists, and code blocks. It includes responsive design considerations for smaller screens and print styles.
```css
html { line-height: 1.5; font-family: "Inter", sans-serif; font-size: 20px; color: #1a1a1a; background-color: #fdfdfd; }
body { margin: 0 auto; padding-left: 50px; padding-right: 50px; padding-top: 50px; padding-bottom: 50px; hyphens: auto; overflow-wrap: break-word; text-rendering: optimizeLegibility; font-kerning: normal; }
@media (max-width: 600px) {
body { font-size: 0.9em; padding: 1em; }
h1 { font-size: 1.8em; }
}
@media print {
body { background-color: transparent; color: black; font-size: 12pt; }
p, h2, h3 { orphans: 3; widows: 3; }
h2, h3, h4 { page-break-after: avoid; }
}
p { margin: 1em 0; }
a { color: #1a1a1a; }
a:visited { color: #1a1a1a; }
img { max-width: 100%; }
h1, h2, h3, h4, h5, h6 { margin-top: 1.4em; }
h5, h6 { font-size: 1em; font-style: italic; }
h6 { font-weight: normal; }
ol, ul { padding-left: 1.7em; margin-top: 1em; }
li > ol, li > ul { margin-top: 0; }
blockquote { margin: 1em 0 1em 1.7em; padding-left: 1em; border-left: 2px solid #e6e6e6; color: #606060; }
code { font-family: Menlo, Monaco, 'Lucida Console', Consolas, monospace; font-size: 85%; margin: 0; }
pre { margin: 1em 0; overflow: auto; }
pre code { padding: 0; overflow: visible; overflow-wrap: normal; }
.sourceCode { background-color: transparent; overflow: visible; }
hr { background-color: #1a1a1a; border: none; height: 1px; margin: 1em 0; }
table { margin: 1em 0; border-collapse: collapse; width: 100%; overflow-x: auto; display: block; font-variant-numeric: lining-nums tabular-nums; }
table caption { margin-bottom: 0.75em; }
tbody { margin-top: 0.5em; border-top: 1px solid #1a1a1a; border-bottom: 1px solid #1a1a1a; }
th { border-top: 1px solid #1a1a1a; padding: 0.25em 0.5em 0.25em 0.5em; }
td { padding: 0.125em 0.5em 0.25em 0.5em; }
header { margin-bottom: 4em; text-align: center; }
#TOC li { list-style: none; }
#TOC ul { padding-left: 1.3em; }
#TOC > ul { padding-left: 0; }
#TOC a:not(:hover) { text-decoration: none; }
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; min-height:1em; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code { counter-reset: source-line 0; }
pre.numberSource code > span { position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before { content: counter(source-line); position: relative; left: -1em; text-align: right; vertical-align: baseline; border: none; display: inline-block; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; padding: 0 4px; width: 4em; color: #aaaaaa; }
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode { }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { col
```
--------------------------------
### CSS Main Body Styling
Source: https://github.com/tyoverby/composition-comparison/blob/main/04-multiplicity/bonsai-2023/index.html
Applies zero padding and margin to the main body element for consistent layout.
```CSS
Main body {
padding: 0;
margin: 0;
}
```
--------------------------------
### React App with useReducer for Dynamic Components
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
This snippet demonstrates a React application that uses the `useReducer` hook to manage two independent states: the number of subcomponents to render and the state of each subcomponent. It dynamically creates subcomponents based on the 'howMany' state and passes down a specific reducer function to each.
```jsx
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';
import Counter from '../../shared/Counter';
import { applyAction as counterApplyAction, defaultState as counterDefaultState } from '../../shared/Counter';
const defaultState = {};
function applyAction(state, { which, subAction }) {
return {
...state,
[which]: counterApplyAction(state[which] || 0, subAction, 1),
};
}
const App = () => {
let [howMany, injectHowMany] = useReducer(
(state, action) => counterApplyAction(state, action, 1),
counterDefaultState
);
let [subcomponentState, subcomponentInject] = useReducer(applyAction, defaultState);
let subcomponents = Array.from({ length: howMany }, function (_, i) {
let injectMe = (subAction) => subcomponentInject({ which: i, subAction });
return (
);
});
return (
{subcomponents}
);
};
ReactDOM.render(, document.getElementById('app'));
```
--------------------------------
### React Counter Component Usage
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
Illustrates the React implementation for a counter component, using `useReducer` for state management and passing the state and an action dispatcher to the component.
```javascript
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';
import Counter, { applyAction, defaultState } from '../../shared/Counter';
const App = () => {
let [state, inject] = useReducer(
(state, action) => applyAction(state, action, 1),
defaultState
);
return ;
};
ReactDOM.render(, document.getElementById('app'));
```
--------------------------------
### React Sequential Composition
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Illustrates sequential composition in React. The `applyAction` function is modified to handle the dependency where one counter's state affects another.
```React
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';
import Counter,
{
applyAction as counterApplyAction,
defaultState as counterDefaultState,
}
from '../../shared/Counter';
const defaultState = {
first: counterDefaultState,
second: counterDefaultState,
};
function applyAction(state, { which, subAction }) {
switch (which) {
```
--------------------------------
### Elm Dynamic Counter Component
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
This Elm code implements dynamic rendering of counter components. It manages the state of a 'how many' counter and a dictionary of other counter components, updating and displaying them based on the 'how many' value.
```elm
module Main exposing (main)
import Browser
import Counter
import Dict exposing (Dict)
import Html exposing (Html, div, map)
type alias Model =
{ howMany : Counter.Model, others : Dict Int Counter.Model }
init : Model
init =
{ howMany = Counter.init, others = Dict.empty }
type Msg
= HowMany Counter.Msg
| ForKey Int Counter.Msg
updateOther which msg =
Dict.update which
(\_ ->
Just (Counter.update 1 msg (Maybe.withDefault 0 m))
)
update : Msg -> Model -> Model
update appMsg model =
case appMsg of
HowMany msgHowMany ->
{ model | howMany = Counter.update 1 msgHowMany model.howMany }
ForKey which msg ->
{ model | others = updateOther which msg model.others }
viewOther : Dict Int Counter.Model -> Int -> Html Counter.Msg
viewOther models key =
case Dict.get key models of
Just model ->
Counter.view 1 (String.fromInt key) model
Nothing ->
Counter.view 1 (String.fromInt key) Counter.init
view : Model -> Html Msg
view model =
List.range 0 (model.howMany - 1)
|> List.map (i -> Html.map (ForKey i) (viewOther model.others i))
|> List.append [ Html.map HowMany (Counter.view 1 "how many" model.howMany) ]
|> div []
main =
Browser.sandbox { init = init, update = update, view = view }
```
--------------------------------
### Elm Counter Component
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
An Elm module defining a counter component. It exports the initial model, update function, and view calculations. The update and view functions require the increment/decrement amount and a label.
```elm
module Counter exposing (Model, Msg, init, update, view)
import Browser
import Html exposing (Html, div, span, text)
import Html.Events exposing (onClick)
type alias Model =
Int
init : Model
init =
0
type Msg
= Increment
| Decrement
update : Int -> Msg -> Model -> Model
update howMuch msg model =
case msg of
Increment ->
model + howMuch
Decrement ->
model - howMuch
view : Int -> String -> Model -> Html Msg
view howMuch label model =
let
button op action =
Html.button [ onClick action ] [ text (String.concat [ op, String.fromInt howMuch ]) ]
in
div []
[ text (String.concat [ label, ": " ])
, button "-" Decrement
, text (String.fromInt model)
, button "+" Increment
]
;;
```
--------------------------------
### React Counter Component
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
A React implementation of a counter component. It includes default state, an `applyAction` function to manage state changes based on a delta, and a functional component that renders the label, buttons for increment/decrement, and the current state.
```JavaScript
import React from 'react';
export const defaultState = 0;
export function applyAction(state, action, by) {
switch (action) {
case 'increment':
return state + by;
case 'decrement':
return state - by;
default:
console.error('BUG');
}
}
const Counter = ({ label, by, state, inject }) => {
let increment = () => inject('increment');
let decrement = () => inject('decrement');
return (
{label}:
{state}
);
};
export default Counter;
```
--------------------------------
### React Parallel Composition
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Illustrates parallel composition in React using `useReducer`. Two counter components are rendered independently with their own state and dispatch functions.
```React
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';
import Counter, { applyAction, defaultState } from '../../shared/Counter';
const App = () => {
let [state1, inject1] = useReducer(
(state, action) => applyAction(state, action, 1),
defaultState
);
let [state2, inject2] = useReducer(
(state, action) => applyAction(state, action, 1),
defaultState
);
return (
);
};
ReactDOM.render(, document.getElementById('app'));
```
--------------------------------
### Elm Counter Component
Source: https://github.com/tyoverby/composition-comparison/blob/main/index.html
Implements a counter component in Elm. It defines the model, messages for incrementing and decrementing, an update function to handle state changes based on the delta, and a view function to render the counter with a label and buttons.
```Elm
module Counter exposing (Model, Msg, init, update, view)
import Browser
import Html exposing (Html, div, span, text)
import Html.Events exposing (onClick)
type alias Model =
Int
init : Model
init =
0
type Msg
= Increment
| Decrement
update : Int -> Msg -> Model -> Model
update howMuch msg model =
case msg of
Increment ->
model + howMuch
Decrement ->
model - howMuch
view : Int -> String -> Model -> Html Msg
view howMuch label model =
let
button op action =
Html.button [ onClick action ] [ text (String.concat [ op, String.fromInt howMuch ]) ]
in
div []
[ text (String.concat [ label, ": " ])
, button "-" Decrement
, text (String.fromInt model)
, button "+" Increment
]
```
--------------------------------
### React Dynamic Counter Component
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
This React code dynamically renders multiple counter components. It uses two useReducer hooks: one for the main 'how many' counter and another for managing the state of the dynamically generated sub-counter components.
```jsx
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';
import Counter, {
applyAction as counterApplyAction,
defaultState as counterDefaultState,
} from '../../shared/Counter';
const defaultState = {};
function applyAction(state, { which, subAction }) {
return {
...state,
[which]: counterApplyAction(state[which] || 0, subAction, 1),
};
}
const App = () => {
let [howMany, injectHowMany] = useReducer(
(state, action) => counterApplyAction(state, action, 1),
counterDefaultState
);
let [subcomponentState, subcomponentInject] = useReducer(applyAction, defaultState);
let subcomponents = Array.from({ length: howMany }, function (_, i) {
let injectMe = (subAction) => subcomponentInject({ which: i, subAction });
return (
);
});
return (
{subcomponents}
);
};
ReactDOM.render(, document.getElementById('app'));
```
--------------------------------
### React Sequential Composition
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
React code for sequential composition, using a single reducer to manage state updates from two counter components, allowing them to witness each other's changes.
```jsx
import React, { useReducer } from 'react';
import ReactDOM from 'react-dom';
import Counter, {
applyAction as counterApplyAction,
defaultState as counterDefaultState,
} from '../../shared/Counter';
const defaultState = {
first: counterDefaultState,
second: counterDefaultState,
};
function applyAction(state, { which, subAction }) {
switch (which) {
case 'first':
return {
...state,
first: counterApplyAction(state.first, subAction, 1),
};
case 'second':
return {
...state,
second: counterApplyAction(state.second, subAction, state.first),
};
}
}
const App = () => {
let [state, inject] = useReducer(applyAction, defaultState);
let injectFirst = (subAction) => inject({ which: 'first', subAction });
let injectSecond = (subAction) => inject({ which: 'second', subAction });
return (
);
};
ReactDOM.render(, document.getElementById('app'));
```
--------------------------------
### React Counter Component (JSX)
Source: https://github.com/tyoverby/composition-comparison/blob/main/readme.md
A React counter component implemented in JSX. It exports default state and a state transition function. The component accepts label, delta, state, and an inject function as props.
```jsx
import React from 'react';
export const defaultState = 0;
export function applyAction(state, action, by) {
switch (action) {
case 'increment':
return state + by;
case 'decrement':
return state - by;
default:
console.error('BUG');
}
}
const Counter = ({ label, by, state, inject }) => {
let increment = () => inject('increment');
let decrement = () => inject('decrement');
return (
{label}:
{state}
);
};
export default Counter;
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.