Creating Reactive DOM Elements with SolidJS Signals: A Comprehensive Guide

Question for Beginners - I am using SolidJS and I need help making DOM elements react to signal updates.

I am experiencing issues with two instances that are not updating as expected:

  1. In the Main Component, when trying to update the item count.
  2. In the Secondary Component, when trying to update the item results.

Main Component

import { Component } from 'solid-js'
import { isEqual as _isEqual } from 'lodash-es'

const [getItems, setItems] = createSignal<Array<Item>>([])

const MainComponent: Component = () => {
    const updateItems = (item: Item) => {
        const initialItems = getItems()
        const index = initialItems.findIndex(i => _isEqual(i, item))

        index == -1 ? initialItems.push(item) : initialItems.splice(index, 1)

        setItems(initialItems)
    }

    return (
        <>
            <span>Total Items: {getItems().length}</span> //       << -- WON'T UPDATE.
            <button onclick={() => updateItems(x: Item)}>Click Me</button>
        </>
    )
}

export { MainComponent, getItems }

Secondary Component

import { Component } from 'solid-js'
import { getItems } from '../MainComponent'

const SecondaryComponent: Component = () => {
    return (
        <p class='results'>
            {getItems() ? 'Contains Items' : 'No Items'} //        << -- WILL NOT CHANGE.
        </p>
    )
}

Answer №1

As per the information provided in Solid's API documentation regarding the function createSignal (found in the options section):

By default, when you call a signal's setter, the signal will only update (and trigger dependent functions to rerun) if the new value is actually different from the old value, based on JavaScript's === operator.

In this specific scenario, the array being set in the signal remains identical (===) to the previous one. One way to address this is by disabling referential equality checks for the signal, like so:

createSignal<Array<Item>>([], { equals: false })
.

Alternatively, you can opt to create a new array each time you set the array again, such as with: setItems([...init])

Answer №2

Components are not just regular DOM elements; they are transformed into DOM elements during compilation while also having additional features for reactivity.

If you want to modify an array, remember that in order to trigger a state update, you need to assign a new array rather than mutating the existing one.

const [items, setItems] = createSignal([]);

setInterval(() => {
  setItems([ ...items(), items().length ]);
}, 1000);

Therefore, creating a new array and adhering to JSX guidelines should resolve your issue.

To future-proof this question, let's explore updating a real DOM element that exists outside of Solid's system.

Initially, I will generate a new DOM element and insert it into the body, although the process remains consistent for modifying an already present DOM element.

import { createSignal, createEffect } from "solid-js";

// Retrieve the DOM element
const el = document.createElement('div');
document.querySelector('body').appendChild(el);

// Signal for the content within our DOM element
const [count, setCount] = createSignal(0);

// Utilizing setInterval to update the signal for simplicity
setInterval(() => {
  setCount(c => c + 1);
}, 1000);

// Implementing an effect to update the element's innerText or innerHTML upon signal changes
createEffect(() => {
  el.innerHTML = count();
});

This solution has a minor issue; the effect we established may not be disposed when its scope is disposed as it doesn't belong to any tracking scope.

The recommended approach is to execute this code within a render function that automatically generates a root or manually create one using createRoot and dispose it accordingly.

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

Enhancing component and view functionality in Angular

Recently, I started working on Angular 11 and encountered a simple yet challenging question. Despite my best efforts, I have been unable to find a suitable answer. In an attempt to utilize Object-Oriented Programming (OOP) concepts within Angular, I create ...

Using this functionality on a ReactJS Functional Component

Hey everyone, I'm fairly new to using React and I'm currently trying to wrap my head around some concepts. After doing some research online, I stumbled upon a situation where I am unsure if I can achieve what I need. I have a functional componen ...

What is the best way to store a username and password within a JavaScript object in ReactJS?

I am encountering an issue with obtaining the login credentials from the object. Although the code snippet below functions perfectly well with other forms. SignIn.js export default function SignIn(props) { const [state, setState] = useState({ userna ...

Steps for converting a window to a PDF file rather than an XPS file

Whenever I attempt to print the contents of my HTML page using window.print(), it always creates an XPS file. However, what I really need is for it to generate a PDF file instead. Any assistance would be greatly appreciated. Thank you! ...

Discovering the way to retrieve background height following a window resize using jQuery

Is there a way to obtain the background height once the window has been resized? div { background-image: url(/images/somebackground.jpg); background-size: 100% 90%; background-repeat: no-repeat; width: 70%; background-size: contain; ...

I attempt to use the OBJECT3D array

As a beginner with Three.js, I am trying to add my 'model' object to an array. I believe my code is correct. I have declared my variable as nextobj = [ ];. function Loadobj() { var mx = [-1500,1500] , my = [350,350] , mz = [-1000,-1000]; ...

Navigating through an array with multiple dimensions and varying lengths using d3

I am working with a multidimensional array of integer values to create a dynamic bar graph using d3.js. The challenge lies in the fact that each row can have a variable number of values. My goal is to generate color-coded rectangles for each row based on t ...

Advantages of using jQuery's .each() function instead of conventional "for" loops

I recently had a colleague recommend using jQuery's .each() function instead of a standard javascript for loop for traversing through DOM elements on my webpage. While I am familiar with jQuery, I've always wondered why developers prefer using .e ...

The mesh takes on a more defined geometric shape once it has been processed using ThreeCSG

When I use ThreeCSG to subtract one mesh from another, I encounter a problem. The main mesh is a ring and the mesh to subtract is a diamond. Initially, the scene looks fine: Mesh fine. However, after subtracting the meshes, the ring become angular: Mesh Br ...

Issue with NodeJS Express's reverse proxy due to an invalid TLS certificate alternative name

I have configured a reverse proxy on my endpoint as shown below: var express = require('express'); var app = express(); var httpProxy = require('http-proxy'); var apiProxy = httpProxy.createProxyServer(); var serverOne = 'https://i ...

When attempting to send a POST request to /api/users/login, the system returned an error stating that "

Is there a way to make a post request to the mLab Database in order to determine if a user account already exists? The server's response states that the User is not defined. Can you please review my code? // @route post api/user/login# router.post(& ...

Tips for rearranging sibling divs while maintaining the order of their child elements

Is there a way to shuffle the order of div classes shuffledv, while maintaining the same order of id's each time the page is refreshed? <div class="shuffledv"> <div id="2"></div> <div id="3"></div> <div id="1">< ...

I can't seem to figure out why my three.js scene refuses to render

I have the following contents in my main.js file: import './style.css'; import * as THREE from 'three'; // Create a new scene const scene = new THREE.Scene(); // Define the camera with arguments for field of view, aspect ratio, and v ...

Guide on deploying Google App Script add-ons on Google Workspace Marketplace

Recently delving into Google App Script, I've taken my first steps in coding within the platform. Utilizing the deploy option provided by Google App Script, I successfully launched my app. However, upon deployment, I encountered difficulty locating my ...

A guide on showcasing a MultiPolygon GeoJSON on a Leaflet map

I am attempting to showcase a GeoJSON MultiPolygon object on a Leaflet map. I retrieve it from a PostgreSQL database as JSON and transform it into GeoJSON. I have validated the MultiPolygon object on GeoJSONLint and it checks out: However, I am facing di ...

React Native app experiences a start-up crash caused by SoLoader problem

I'm encountering a problem with my Android app (iOS is working fine). Every time I build it, the application closes before launching. I've tried various solutions found on Github and here, but haven't been able to resolve it yet. The instal ...

Using AngularJS to create interactive popups within leaflet maps

My map uses leafletjs to create markers such as ev124, ev125, and so on. In addition, there are links with a key attribute like <a ng-click="popup(evsi)" key="124">link</a> Using angular, I extract the key value this way: $scope.popup= funct ...

Why won't my div tag show conditionally with AngularJS ng-show?

I'm having trouble displaying a div tag on a form based on the boolean flag specified in ng-show. Unfortunately, the div is not showing up at all. Here's what I've tried so far without success. Any assistance would be greatly appreciated! F ...

Using jQuery to loop through a table and retrieve the button value from every row

I have a challenge with dynamically created buttons in a table. My goal is to loop through the table, identify the rows that have a checked checkbox, and retrieve the value of a button within that row. I then need to store these values in an array. Unfortu ...

Avoid constantly updating the rendering in React by utilizing callback functions

Is there a way to prevent Component B from rendering when I am only making changes in Component A? For example, if console.log("A") is associated with Component A and console.log("B") with Component B, I expect that updating text in Component A will only ...