@travisWaithMair
non-traditional.dev
import { render } from "solid-js/web";
import { createSignal } from "solid-js";
function Counter() {
const [count, setCount] = createSignal(0);
const increment = () => setCount(count() + 1);
return (
<button type="button" onClick={increment}>
{count()}
</button>
);
}
render(() => <Counter />, document.getElementById("app")!);
function Welcome(props) {
return <p>Welcome, {props.name}</p>;
}
const [user, setUser] = createSignal();
createEffect(() => {
getUser(props.id)
.then(user => {
setUser(user)
})
})
Unlike frameworks like Preact, one cannot just use existing React components in a Solid Application.
img src: https://tonynguyenit.medium.com/
Solid JS will surgically update only those parts of the App that are dependent on reactive values
function Counter() {
const [count, setCount] = createSignal(1);
const increment = () => setCount(count() + 1);
console.log("I only get logged once")
return (
<button type="button" onClick={increment}>
{count()}
</button>
);
}
Components in Solid "disappear" after the initial render.
Solid is built on "fine-grained" reactive primitives that do the heavy lifting of optimizing DOM updates.
Everything in Solid can be broken down into a Signal, a Memo, or an Effect.
createSignal
const [count, setCount] = createSignal(0);
<p>The current count is: {count()}</p>
<button onClick={() => setCount(count() + 1)}>
Increment
</button>
Signals are simply functions that return a value. They are used to keep reactive state.
createEffect
createEffect(() => {
document.title = `The current count is: ${count()}`;
});
*No Dependency Array needed
Effects let you do actions based on when signals update.
createEffect
createEffect(() => {
document.title = "I'm not reactive";
});
This effect will only run once since there are no reactive values that will trigger an update
If there are no reactive values, they don't update.
createMemo
const fullName = createMemo(() => `${firstName()} ${lastName()}`);
<p>{fullName()}</p>
It is both an effect and a signal
Works best for expensive calculations
Simple Counter Example
function Counter() {
const [count, setCount] = createSignal(0);
createEffect(() => {
document.title = `The current count is: ${count()}`;
});
return (
<div>
<p>The current count is: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Plus</button>
</div>
);
}
The effect and paragraph are updated when ever the count signal is updated
A More Complicated Counter Example
function Counter() {
const [count, setCount] = createSignal(0);
const [myName, setMyName] = createSignal("Travis");
createEffect(() => {
document.title = `The current count is: ${count()}`;
});
return (
<div>
<p>The current count is: {count()}</p>
<input value={myName()} onChange={e=>setMyName(e.target.value)}/>
<button onClick={() => setCount(count() + 1)}>Plus</button>
</div>
);
}
The effect and paragraph are only updated whenever the count signal is updated, but not when the myName value is updated
Primitives don't follow React's Hook rules
export const [count, setCount] = createSignal(0);
function Counter(props) {
if(props.logCount){
createEffect(() => {
console.log(count());
});
}
return (
<div>
<p>The current count is: {count()}</p>
<button onClick={() => setCount(count() + 1)}>Plus</button>
</div>
);
}
Universidad
Presidente
Embarazada?
University
President
Embarrassed
function DataDisplay(props){
if(props.data === undefined){
return <div>Loading...</div>
}
return <div>{/* display props.data */}</div>
}
function DataDisplay(props){
if(props.data === undefined){
return <div>Loading...</div>
}
/**
* This code is never run, which
* means the reactivity is never
* wired up.
*/
return <div>{/* display props.data */}</div>
}
import { Show } from "solid-js";
function DataDisplay(props){
return (
<Show when={props.data} fallback={<div>Loading...</div>}>
<div>{/* display props.data */}</div>
</Show>
);
}
<Switch fallback={<div>Not Found</div>}>
<Match when={state.route === "home"}>
<Home />
</Match>
<Match when={state.route === "settings"}>
<Settings />
</Match>
</Switch>
<For
each={state.list}
fallback={<div>Loading...</div>}
>
{(item) => <div>{item}</div>}
</For>
<Suspense fallback={<div>Loading...</div>}>
<AsyncComponent />
</Suspense>
<ErrorBoundary
fallback={
(<div>
Something went terribly wrong
</div>)
}
>
<MyComp />
</ErrorBoundary>
function DoubleCounter() {
const [count, setCount] = createSignal(0);
const doubleCount = count() * 2 //NO NO
return (
<div>
<p>The double count is: {doubleCount}</p>
<button onClick={() => setCount(count() + 1)}>Plus</button>
</div>
);
}
function DoubleCounter() {
const [count, setCount] = createSignal(0);
const doubleCount = () => count() * 2
return (
<div>
<p>The double count is: {doubleCount()}</p>
<button onClick={() => setCount(count() + 1)}>Plus</button>
</div>
);
}
OR.....
function DoubleCounter() {
const [count, setCount] = createSignal(0);
return (
<div>
<p>The double count is: {count()*2}</p>
<button onClick={() => setCount(count() + 1)}>Plus</button>
</div>
);
}
function Greeting({salutation, name}){
return <p>{salutation}, {name}</p>
}
// or
function Greeting(props){
const {salutation, name} = props
return <p>{salutation}, {name}</p>
}
props = {
salutation:'Hello',
get name(){
return userName()
}
}
<Greeting salution="Hello" name={userName()}/>
function Greeting(props}){
return <p>{props.salutation}, {props.name}</p>
}
// default props
props = mergeProps({ name: "Smith" }, props);
// clone props
newProps = mergeProps(props);
// merge props
props = mergeProps(props, otherProps);
Solid also provides the splitProps and mergeProps utility functions.
These utilities allow you to safely split or merge props without breaking reactivity.
function MyComponent(props) {
const [local, others] = splitProps(props, ["children"]);
return (
<>
<div>{local.children}</div>
<Child {...others} />
</>
);
}
function MyInlineStyle()
return (
<p
style={{
color:'blue',
backgroundColor: 'olivedrab'
}}
>
{/*...*/}
</p>
);
}
function MyInlineStyle()
return (
<p
style={{
color:'blue',
'background-color': 'olivedrab',
'--my-custom-property': '100px'
}}
>
{/*...*/}
</p>
);
}
or ....
function MyInlineStyle()
return (
<p
style={`
color: blue;
background-color': olivedrab;
--my-custom-property: 100px;
`}
>
{/*...*/}
</p>
);
}
import { onMount } from "solid-js";
function MyForm() {
const handleSubmit = (e) => {
/* handle submit */
};
let myInput;
onMount(() => myInput.focus());
return (
<form onSubmit={handleSubmit}>
<input ref={myInput} />
</form>
);
}
npm install --save-dev eslint eslint-plugin-solid
# or
pnpm add --save-dev eslint eslint-plugin-solid
yarn add --dev eslint eslint-plugin-solid
# optional, to create an ESLint config file
npx eslint --init
# or
pnpm eslint --init
yarn eslint --init
StateofJS 2021 results
Solid has the highest Satisfaction rating
Shameless plug for Solid Bedrock Layout
For example, TanStack has "Solid" versions of their popular tools like TanStack-Query and TanStack Table
SolidStart enables you to render your application in different ways depending on your use case:
Playground:
https://discord.gg/solidjs