SolidJS createEffect will only trigger on changes after the initial rendering

When I was searching for a solution, I came across the need to only trigger a reaction after my component had been rendered for the first time.

For instance:

function InputName() {
  const [name, setName] = createSignal("");
  const [nameError, setNameError] = createSignal<string | null>(null);

  createEffect(() => {
    setNameError(name().length > 0 ? null : "Name is required");
  })

  return <div>
    <input type="text" placeholder="Name" value={name()} onInput={(e) => setName(e.currentTarget.value)} />
    <Show when={nameError()}>
      <div>{nameError()}</div>  
    </Show>
  </div>
}

Unfortunately, this set the error right away.

The challenge then became how to execute the createEffect function only after the initial render during a change event.

I searched everywhere for an answer but couldn't find one. I will share my solution as a response here in case someone else encounters a similar situation.

Answer №1

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:

  1. Controlled Inputs: State updates immediately based on user actions like key presses.
  2. 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

Answer №2

One technique that proved successful for me was utilizing the on function in conjunction with defer: true:

function InputName() {
  const [name, setName] = createSignal("");
  const [nameError, setNameError] = createSignal<string | null>(null);

  createEffect(on(name, (name) => {
    setNameError(name.length > 0 ? null : "Name is required");
  }, { defer: true }));

  return <div>
    <input type="text" placeholder="Name" value={name()} onInput={(e) => setName(e.currentTarget.value)} />
    <Show when={nameError()}>
      <div>{nameError()}</div>
    </Show>
  </div>
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips on integrating JavaScript with embedded Ruby code

I am attempting to generate a flash message that displays after a user clicks a link in my js.erb file. $('a').click(function(){ <% flash.now[:alert]= "Successfully added "%> this.innerHTML <% "to cart" %> }) M ...

discord.js tutorial on cutting a hyperlink

i'm developing a Steam command that takes either the ID or profile link as arguments. My aim is to extract the last word. eg: https://steamcommunity.com/id/ethicalhackeryt/ here, I want to extract ethicalhackeryt or if the user directly inputs it the ...

"Learn how to update an existing table row and populate its cells with JSON data retrieved from a successful AJAX request without creating a

Currently, I am utilizing CouchCMS. The platform offers a feature known as repeatable regions which essentially generates tables to showcase recurring content. The defined repeatable region looks like this: <cms:repeatable name="item_detail" ...

Identifying Master Page Controls Post-Rendering

Within my asp.net projects, I have noticed a discrepancy in the control id on the master page's Contentplaceholder1. On my local server, the id appears as "ctl00_Contentplaceholder1_control" after rendering. However, when the application is deployed t ...

An issue with Axios request in a cordova app using a signed version

Currently, I am in the process of developing a Cordova application utilizing Axios and React. The interesting part is that everything runs smoothly when I build the app with Cordova and test it on my phone using the APK. However, once I sign, zipalign it, ...

Encountering an issue while attempting to assess a Meteor package within a local environment

Hello everyone! I'm a beginner in Meteor programming and currently following the online book discovermeteor.com. I recently came across a chapter that covers the creation of Meteor Packages. Excitedly, I proceeded to create my own package using the ...

What causes the string to be treated as an object in React Native?

I am fetching a string value through an API and I need to display it in the View. However, the string value is coming as a Promise. How can I handle this? "Invariant Violation: Objects are not valid as a React child (found: object with keys {_40, _65 ...

Encountering an issue with receiving "undefined" values while utilizing WordPress post metadata in AngularJS

Utilizing the Wordpress REST API v2 to fetch data from my functional Wordpress website to an AngularJS application. Everything is functioning properly, however when I attempt to access post meta such as "_ait-item_item-data", it returns an error stating "u ...

Send the user back to the homepage without the need to refresh the page

When the user clicks "Okay" in my window.prompt, the code below opens a new tab. Is there a way to direct the user to the home page without opening a new tab? if (window.confirm("Do you really want to leave?")) { window.open("./Tutoria ...

Exploring the intersection of onBeforeUnload and node.js

I just started learning about node.js. I'm curious if onbeforeunload can be used in node.js. If so, will the "no script" plugin for Firefox block scripts created by node.js? I want to inform my visitors with a message before they leave the page withou ...

Tips for transforming C#.NET code into JavaScript code

A few years back (around 3 or 4 years ago), I recall hearing about a fascinating concept that involved generating client-side JavaScript code from C#.NET source code. It may have been related to validation tasks specifically... Does anyone have more inform ...

Error with Ant Design Autocomplete functionality when searching for a number

I am currently using ant design to develop a more advanced autocomplete component that will display data from multiple columns. In this particular scenario, I have two columns named tax_id and legal_name that users can search by. Everything works smoothly ...

A method to find the sum of the final n elements in an array by employing Arr.reduceRight

I have successfully calculated the sum of the last n elements in an array using a for loop. Is it possible to achieve the same result using Arr.reduceRight instead? x = [1,2,3,4,5]; y = 0 for(let i=x.length; i>x.length-3; i--) { console.log(x[i-1]); ...

Ensuring precise accuracy in JavaScript; transforming 0.5 into 0.5000

My current challenge involves converting every fraction number to n decimal places in JavaScript/Node.js. However, I've encountered a roadblock as it appears impossible to convert 0.5 to 0.5000. This discrepancy is causing my test cases that anticipat ...

Is it possible to stack one Canvas on top of another?

Right now, I am engaged in a process that involves: creating a canvas and attaching it to a division applying a background image through CSS to that canvas. drawing a hex grid on the canvas placing PNGs on the canvas. animating those PNGs to show "movem ...

Animate specifically new items in a list rendered via ngFor in Angular animation

I am working with a list of array items in an ngFor loop. I have a basic button that adds an item to the array. My goal is to apply an animation only to the newly added items, but currently all the existing list items also receive the animation upon page l ...

Is there a way to create triangles on all four corners of an image using canvas in JavaScript?

In my code, I am currently working on drawing rectangles on the corners of an image using JavaScript. To achieve this, I first extract the image data from a canvas element. // Get image data let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height) ...

Put emphasis on the input field - React component

My React component features an input field with a disabled attribute. When the component is clicked, the input becomes enabled for the user to type in. I have successfully implemented this functionality so far, but now I need to focus on the input field on ...

Issues with Google Fonts failing to load correctly

Would you mind taking a look at this issue for me? In all browsers except Firefox, the expected behavior is that a web font remains invisible until fully loaded, preserving space on the page. Interestingly, in Chrome and IE9 (the browsers I tested), ther ...

JSON data cannot be transmitted using AJAX

I created a function that tracks the time spent on a specific page and where the user came from. The data is collected and saved into a JSON object, but I encountered an issue when trying to send this JSON via ajax. Upon successful sending, I receive an em ...