npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@santerijps/elm-react

v0.2.2

Published

An attempt to introduce an Elm -like feel when developing React apps.

Downloads

9

Readme

elm-react

elm-react is an attempt to introduce an Elm -like feel when developing React apps. This is achieved with a custom hook (useElm) that utilizes React's useReducer to smoothly update the state when needed.

elm-react reintroduces some of the terminology found in Elm, so in your components you'll

  • Define your own Model type to represent the component state
  • Define your own component messages with the Msg type
  • Use the Cmd<T> type when you want to mutate your state and re-render your view
  • Implement the init, update and view functions

Check out the official Elm documentation to get a better idea of how Elm architecture plays out.

Install

npm i @santerijps/elm-react

Example usage

Compare the example below to the example found in Elm's documentation to see how similar they look.

Disclaimer: The below example is trying to mimic the exact look of Elm. In real usage, you would most likely implement it differently ;)

import { Update, View, useElm } from "@santerijps/elm-react";



// MAIN


export default function Counter() {
  return useElm({ init, update, view });
}



// MODEL


type Model = number;


const init = () =>
  0



// UPDATE


type Msg = 'Increment' | 'Decrement'


const update = ({ msg, model }: Update<Model, Msg>) =>
  ( msg == 'Increment' ? model + 1
  : msg == 'Decrement' ? model - 1
  : model
  )



// VIEW


const view = ({ cmd, model }: View<Model, Msg>) =>
  <div>
    <button onClick={cmd.Decrement}>{'-'}</button>
    <div>{model}</div>
    <button onClick={cmd.Increment}>{'+'}</button>
  </div>

Example: todo-app

import {  Maybe, Update, View, useElm } from '@santerijps/elm-react';
import { ImmutableList } from '@santerijps/elm-react/helpers';

export default function Todo() {
  return useElm({ init, update, view });
}

type Item = {
  done: boolean;
  text: string;
};

type Model = {
  items: ImmutableList<Item>;
  input: string;
};

type Msg
  = 'UpdateInput'
  | 'AddItem'
  | 'ClickItem'

function init(): Model {
  return {
    items: new ImmutableList,
    input: '',
  };
}

function update({ args, model, msg }: Update<Model, Msg>): Maybe<Model> {
  switch (msg) {

    case 'UpdateInput': {
      const [ event ] = args as [Event];
      event.preventDefault();
      const input = event.target as HTMLInputElement;
      return { input: input.value };
    }

    case 'AddItem': {
      const [ event ] = args as [Event];
      event.preventDefault();
      if (model.input.length > 0) {
        return {
          input: '',
          items: model.items.append({text: model.input, done: false}),
        };
      } else {
        return undefined;
      }
    }

    case 'ClickItem': {
      const [ index ] = args as [number];
      if (model.items.at(index).done) {
        return { items: model.items.removeAt(index) };
      } else {
        return { items: model.items.updateAt(index, {done: true}) };
      }
    }

  }
}

function view({ cmd, model }: View<Model, Msg>) {
  return (
    <main>
      <form onSubmit={cmd.AddItem}>
        <input type="text" placeholder="Add new item" value={model.input} onInput={cmd.UpdateInput} />
      </form>
      <ul>
        {model.items.map((item, index) => (
          <li key={index} onClick={cmd.ClickItem.curry(index)}>
            {item.done ? <s>{item.text}</s> : <>{item.text}</>}
          </li>
        ))}
      </ul>
    </main>
  );
}

Best practices

  • Don't use React's useRef hook in Elm components
    • It's an anti-pattern
    • It doesn't fit well in the Elm architecture
  • Don't mutate your model's arrays
    • I.e. Don't do model.myArray.push(123); return {myArray};
    • Use something like ImmutableList (imported from @santerijps/elm-react/helpers) to deal with updating the array