Vanic
A small, Hook-based library for creating Reactive-UI.
Vanic is an html-attribute
first.
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