Vanic

A small, Hook-based library for creating Reactive-UI.

Vanic is an html-attribute first.

ci npm version License download-url gzip

Features

  • Small.
  • Reactive-UI.
  • Hooks.
  • SSR via renderToString without external deps.
  • More.

Examples

Html-Attribute First

In vanic, event and more will convert to html-attribute.

Install

NPM or Yarn

npm i vanic
// or
yarn add vanic

Browser

<!-- html head -->
<script src="//unpkg.com/vanic"></script>

Deno

import {...} from "https://deno.land/x/vanic/mod.ts";

// more code

Usage Jsx

/** @jsx h */
import { h, render, useEffect, useState } from "vanic";

const Counter = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // log counter
    console.log(count);
  }, [count]);

  return (
    <div>
      <button onclick={() => setCount(count + 1)}>Increment</button>
      <h2>{count}</h2>
    </div>
  );
};

render(<Counter/>, document.getElementById("app"));

Usage Browser

const { html, comp, render, useEffect, useState } = Vanic;

const Counter = comp(() => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // log counter
    console.log(count);
  }, [count]);

  return html`
    <div>
      <button onclick="${() => setCount(count + 1)}">Increment</button>
      <h2>${count}</h2>
    </div>
  `
});

render(Counter, document.getElementById("app"));

Server Side

/** @jsx h */
import { h, renderToString } from "vanic";

const Home = () => {
  return <h1>Hello Home</h1>;
};

const str = renderToString(<Home/>);
console.log(str);
// send str to server.

Hooks

UseState

const [state, setState] = useState(0);
// or
const [state, setState, getState] = useState(0);

note: getState for live state.

UseEffect & UseLayoutEffect

useEffect(() => {
  // code
  return () => {
    // cleanup
  };
}, [/* deps */]);

UseReducer

const [state, dispatch] = useReducer(reducer, initial, /* initLazy */);

UseMemo

const value = useMemo(() => expensiveFunc(a, b), [a, b]);

UseCallback

const addTodo = useCallback(() => {
  setTodos((prev) => [...prev, "New Todo"]);
}, [todos]);

UseRef

const count = useRef(0);

Note: useRef for access DOM different from React.useRef.

Accesing DOM via useRef

const Home = () => {
  const input = useRef(null);

  return (
    <div>
      <input ref={input} />
      <button onClick={() => input.ref().focus()}>Focus Me</button>
    </div>
  );
};

UseContext & CreateContext

jsx only

const ThemeContext = createContext();

const Home = () => {
  const theme = useContext(ThemeContext);

  return <h1 style={{ color: theme.color }}>Hello Home</h1>;
};

const App = () => {
  return (
    <ThemeContext.Provider value={{ color: 'red' }}>
      <Home/>
    </ThemeContext.Provider>
  )
};

render(<App/>, document.getElementById("app"));

Custom Hook

Very simple with custom hook.

Example handling input.

/** @jsx h */
import { h, render, useState } from "vanic";

// example hook for handling input form.
const useInput = (initState) => {
  const [input, handle] = useState(initState);
  return [
    // object input
    input,

    // handling
    (e) =>
      handle({
        ...input,
        [e.target.id]: e.target.value,
      }),

    // reset
    (obj = {}) => handle({ ...input, ...obj }),
  ];
};

const MyForm = () => {
  const [input, handleInput, resetInput] = useInput({
    name: "",
    address: "",
  });

  const onSubmit = (e) => {
    e.preventDefault();
    console.log(input);
    // => { name: "foo", address: "bar" }

    // reset
    resetInput({ name: "", address: "" });
  };

  return (
    <form onSubmit={onSubmit}>
      <input id="name" value={input.name} onChange={handleInput} />
      <input id="address" value={input.address} onChange={handleInput} />
      <button type="submit">Submit</button>
    </form>
  );
};

render(<MyForm/>, document.getElementById("app"));

Style

Support style as object.

...
<h1 style={{ color: 'red' }}>hello</h1>
...

Fragment

/** @jsx h */
import { h, render, Fragment } from "vanic";

const App = () => {
  return (
    <Fragment>
      <h1>Hello</h1>
    </Fragment>
  )
}

render(<App/>, document.getElementById("app"));

isValidElement

/** @jsx h */
import { h, isValidElement } from "vanic";

const App = () => <h1>Hello</h1>;

console.log(isValidElement(<App/>)); // true

console.log(isValidElement("noop")); // false

console.log(isValidElement({ name: "john" })); // false