Basic Components ================ Mithril, like React, uses a component-based structure. However, unlike React, Mithril comes with routing built in. To make this easier to manage, we will thus split the routing entry point from the main application component. First create the ``src/index.html`` template with the following code: .. code-block:: html <%= htmlWebpackPlugin.options.title %> <% for (var css in htmlWebpackPlugin.files.css) { %> <% } %>
<% for (var chunk in htmlWebpackPlugin.files.js) { %> <% } %> As you can see, there is no difference between how the Mithril application and the React application is installed. However, because we set the install point to the ``src/js/index.js``, we next need to create that file and add the following content: .. code-block:: js import m from "mithril"; import Athena from "./athena.jsx"; import "../styles/app.scss"; const root = document.getElementById("app-entry-point"); m.route(root, "/", { "/": Athena }); This is the core of Mithril's built-in routing system. Note, that we utilized a variable to create a shorthand for Mithril. We use the ``m.route`` function to define all available routes and attach the resulting application to the browser's DOM. The function takes three parameters. The first is the attachmentpoint, specifying where in the DOM to place and render the application. The second is the default route. Whatever you specify here will be shown, if the URL path does not match any of the defined routes. It is thus important, that this route exists in the route definition (the third parameter). The third parameter is the route definition object, which maps URL paths to Mithril components. Here we map the root URL path ``'/'`` to our ``Athena`` component. With the routing set up, the next step is to create our ``athena.jsx`` file and add the following content: .. code-block:: jsx import m from "mithril"; import AriaMenu from "./components/aria-menu.jsx"; export default function Athena() { return { view: (vnode) => { return (
{vnode.children}
); }, }; } As you can see, it basically looks like a React component, with a few small changes: * The React ``return`` statement is inside a function that is called ``view`` and takes a single parameter ``vnode``, similar to class components in React (where this function is called ``render``) * Unlike React, Mithril uses normal HTML lower-case attributes and ``class``. * In Mithril to access the component's state in the ``view`` method, we do not use ``state``, instead all access to state, props, child elements and so on is via the ``vnode`` parameter. In this example here, we use ``{vnode.children}`` to define where the child components are to be inserted (similar to how we used ``{{output}}`` with Ember templates). Our ``Athena`` component uses the ``AriaMenu`` component, thus create a new file ``src/js/components/aria-menu.jsx`` and add the following code: .. code-block:: jsx import m from "mithril"; export default function AriaMenu() { function keyDown(ev) { if (ev.keyCode === 39) { let nextElement = ev.target.parentElement.nextElementSibling; while ( nextElement && (nextElement.getAttribute("role") === "separator" || nextElement .querySelector('*[role="menuitem"]') .getAttribute("aria-disabled") === "true") ) { nextElement = nextElement.nextElementSibling; } if (nextElement) { nextElement.querySelector('*[role="menuitem"]').focus(); } } else if (ev.keyCode === 37) { let previousElement = ev.target.parentElement.previousElementSibling; while ( previousElement && (previousElement.getAttribute("role") === "separator" || previousElement .querySelector('*[role="menuitem"]') .getAttribute("aria-disabled") === "true") ) { previousElement = previousElement.previousElementSibling; } if (previousElement) { previousElement.querySelector('*[role="menuitem"]').focus(); } } } return { view: (vnode) => { return ( ); }, }; } As stated above, we use the ``vnode`` to access everything and here you can see, that all attribute values are available via ``vnode.attrs``. Apart from that, everything works the same as in the equivalent React component. If you now run the dev server .. code-block:: console $ webpack serve --config webpack.conf.js you will see your Mithril application.