Solid provides various solutions, customized for different scenarios. I will discuss each of them individually, with the final one being the solution to the particular problem at hand.
If you require a reaction to a signal change happening just once, it is recommended to use a reaction:
const [count, setCount] = createSignal(0);
const track = createReaction(() => console.log('Running reaction'));
track(() => count());
The callback will execute once when the counter signal is updated. If you want to continue tracking the signal, you must call the track function again:
track(() => count());
If continuous reaction to signal updates is needed, utilize the on
method with defer
set to true:
const [count, setCount] = createSignal(0);
createEffect(on(count, () => {
// Executes in response to signal updates.
}, { defer: true }));
For reacting to changes upon component loading, the best approach is to use onMount
as it runs only once during component initialization.
onMount(() => console.log('Component Mounted'));
In order to verify if a prop value is provided and display an error if it's missing, conditional rendering should be used:
import { render } from "solid-js/web";
import { createSignal, Show } from "solid-js";
function User() {
const [name, setName] = createSignal("");
const handleChange = (event) => {
setName(event.target.value);
}
return (
<Show fallback={<div>Name: {name()}</div>} when={!name()}>
<input value={name()} onChange={handleChange} />
</Show>
);
}
render(() => <User />, document.body);
Note that the state updates after the input loses focus.
Live Demo:
An effect isn't ideal for showing errors for prop validation as it results in unnecessary re-renders post UI rendering.
PS: Initially thought you wanted to validate a prop value, but now understand it's about gathering user information.
To provide better feedback by displaying various errors, it's advisable to show errors when they occur instead of just when the name is empty. This helps enhance the feedback mechanism effectively.
This method eliminates the need for an effect, improving performance by reducing unnecessary re-renders.
import { render } from "solid-js/web";
import { createSignal, Show, batch } from "solid-js";
function User() {
const [name, setName] = createSignal("");
const [error, setError] = createSignal("");
const handleChange = (event) => {
const value = event.target.value;
batch(() => {
if (!value) {
setName(event.target.value);
setError("Name can not be empty");
} else {
setName(event.target.value);
setError("");
}
});
}
return (
<div>
<input value={name()} onChange={handleChange} />
<Show when={error()}><label>{error()}</label></Show>
</div>
);
}
render(() => <User />, document.body);
We batch state updates when updating two signals simultaneously to prevent unnecessary double UI updates. While not a concern here, in real applications, extra renderings can lead to issues like refetching values from remote resources within downstream components.
Live Demo:
A more effective alternative would be using an object or store for managing multiple values simultaneously.
import { render } from "solid-js/web";
import { createSignal, Show } from "solid-js";
function User() {
const [state, setState] = createSignal({
name: "",
nameError: "",
});
const handleChange = (event) => {
const value = event.target.value;
if (!value) {
setState({
name: value,
nameError: "name can not be empty",
});
} else {
setState({
name: value,
nameError: ""
});
}
}
return (
<div>
<input value={state().name} onChange={handleChange} />
<Show when={state().nameError}><label>*{state().nameError}</label></Show>
</div>
);
}
render(() => <User />, document.body);
Live Demo:
On a side note, there are primarily two ways to collect information and provide user feedback:
- Controlled Inputs: State updates immediately based on user actions like key presses.
- Regular Inputs: State changes take place when the user finishes typing and the input loses focus.
While React uses controlled inputs, thereby overwriting default input behavior, Solid retains native behavior.
In Solid, onInput triggers right after a keypress, while onChange occurs when the form field loses focus.
Further insights can be found at: https://github.com/solidjs/solid/discussions/416