Why isn't my Vanilla JS snippet for useState() working as expected? Let's delve into the theory behind the issue

Exploring the realm of functional programming has brought me to the concept of closures, but I find myself struggling to fully grasp it. I've created a state closure resembling one used in React, I am aware of the correct solution to make the code snippet function as expected, however, the underlying theoretical principles remain elusive to me.

const useState = function () {
    let state: maze = {
        size: 0,
    };

    const setState = (newState) => {
        state = { ...newState };
    };

    const myStateObj = {
        state,
        setState,
    };

    return myStateObj;
};

const handleMazeSize = (e: InputEvent) => {
    const newMaze: maze = {
        size: Number((e.target as HTMLInputElement).value),
    };

    console.log(useState().state);
    console.log(useState().setState(newMaze));
    console.log(useState().state); // still size 0, expected the inputted size
};

Why is the modification not taking place?

Answer №1

Your code snippet has two main issues that need to be addressed:

  • Each time the change event is handled, a new state with a value of 0 is created. It is important to persist the state outside of the event handler.
  • The way the state property is exposed only returns a reference to the initial internal state object.

There are multiple solutions to these problems. In the modified code below:

  • The size property in the return object of useState has been replaced by a getter
  • useState is called once before attaching the event listener

const useState = function() {
  let state = {
    size: 0,
  };

  const setState = (newState) => {
    state = { ...newState };
  };

  const myStateObj = {
    get state() { return state; },
    setState,
  };

  return myStateObj;
};

const mazeState = useState();

const handleMazeSize = (e) => {
  const newMaze = {
    size: Number(e.target.value)
  };

  console.log("from:", mazeState.state);
  mazeState.setState(newMaze);
  console.log("to:", mazeState.state);
};

document.querySelector("input").addEventListener("change", handleMazeSize);
<input type="number" value="0">

One alternative solution for the second issue involves exposing the state object once and mutating it, rather than using a get method to retrieve the current internal value. However, this approach opens up the possibility of accidentally editing the internal state from external sources (e.g.

const { state } = useState(); state.foo = "bar"
).

const useState = function() {
  const state = {
    size: 0,
  };

  const setState = (newState) => {
    // Mutate the exposed object
    Object.assign(state, newState);
  };

  const myStateObj = {
    state,
    setState,
  };

  return myStateObj;
};

const mazeState = useState();

const handleMazeSize = (e) => {
  const newMaze = {
    size: Number(e.target.value)
  };

  console.log("from:", mazeState.state);
  mazeState.setState(newMaze);
  console.log("to:", mazeState.state);
};

document.querySelector("input").addEventListener("change", handleMazeSize);
<input type="number" value="0">

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

What is the significance of the appearance of the letters A and J in the console for Objects?

After running console.log() in JavaScript code, you may notice some random letters like A and j before or after the Object description in the Google Chrome browser console. What is the significance of these letters? ...

Rendering JSON maps from MongoDB using Node.js

I am looking to display data from a JSON map in my Express application Here is my code: var b = det.map(function(h) { var soalid = h.id_soal; var idarray = [ ]; for (var i = 0; i < soalid.length; i++) { Soal.findOne({ ...

Is there a way to execute one function before another in JavaScript?

Is there a way to execute the checkifPresentInActiveProjLib function before running the checkifPresentInClosedProjLib function? checkifPresentInActiveProjLib(function(flgAc) { if (flgAc === "active_found") // do something $.ajax(...); / ...

To avoid the sudden appearance of a div on the screen, React is programmed to wait for the

Struggling with preventing a flashing div in React where the error message renders first, followed by props, and finally the props render. The EventsView component includes the following code: view.js var view; if (_.size(this.props.events) !== 0) { vie ...

Find a way to incorporate social media features into a web application that functions intermittently

Currently, I am in the process of developing a social media app and working on integrating a search feature to enable users to find friends. The code I have below seems to be functional at times but not consistent (quite frustrating!) The issue seems to st ...

What is the best way to encode only a specific section of a JavaScript object into JSON format?

Currently, I am in the process of developing a 2D gravity simulation game and I am faced with the challenge of implementing save/load functionality. The game involves storing all current planets in an array format. Each planet is depicted by a Body object ...

Enhancing the theme using material-ui@next and typescript

While developing my theme using material-ui, I decided to introduce two new palette options that would offer a wider range of light and dark shades. To achieve this, I extended the Theme type with the necessary modifications: import {Theme} from "material ...

Resetting the form and validation in AngularJS post form submission

I need help resetting a form and all validation messages after submission. Check out my code on plunker: http://plnkr.co/edit/992RP8gemIjgc3KxzLvQ?p=preview Here is the code snippet: Controller: app.controller('MainCtrl', function($scope) { ...

Guide to using Angular $resource to pass query parameter array

My goal is to implement a feature that allows users to be searched based on multiple tags (an array of tags) using the specified structure: GET '/tags/users?tag[]=test&tag[]=sample' I have managed to make this work on my node server and hav ...

What is the best way to hide the next/previous tabs once the jQuery dataTable has been set up using jSON data

Setting up a jQuery table using JSON data. Despite knowing that there will only be one row, the next/previous tabs are still displayed after the table. Is there a way to remove them? Here is the code for the table: table = $("#retrievedTable").dataTabl ...

Exploring the process of implementing inheritance in TypeScript from a JavaScript class

I am using a JavaScript module to extend a Class for a Custom extended Class. I have written my Custom Class in TypeScript, but I encountered the following error messages: Property 'jsFunc' does not exist on type 'tsClass'.ts(2339) I ...

Ways to implement time delays in For loops?

I'm experimenting with creating a loop that repeats a specific action using setTimeout in JavaScript. setTimeout(function() { console.log("Hey!"); setTimeout(function() { console.log("Hey!"); setTimeout(f ...

Sass is throwing an error message saying 'Module not found' during the compilation process

After installing sass using npm ($npm install sass), I attempted to create a JSON script. Unfortunately, when running it, I encountered an error stating 'Cannot find module'. ...

Obtain data from a popup window and transfer it back to the main parent window

I am having trouble with a pop-up window that contains selections. After the user chooses options, I want those selected options to appear in the main window without refreshing it. I am utilizing JavaScript for this task, but I am struggling to find a way ...

Display the internal array of meteor in the template

Currently, I am working with Meteor and am facing a challenge in accessing values stored within a field that operates as an internal array. After executing the query (with projection), I receive a single record structured like this: { "comments" : [ { "u ...

Calculating the total sum of choices within select2

Currently utilizing Select2, a jQuery library, to generate a dropdown list. Trying to determine how to accumulate the values of each option selected by the user. Here's the code sample: <!DOCTYPE html> <html> <head> <m ...

Tips on running a particular code following an AJAX request

My code includes a function that utilizes ajax to populate a select element with options from my database. Below is the function: function RetrieveRole(roleElement) { $.ajax({ type: "POST", url: "IROA_StoredProcedures.asmx/RetrieveRole", dat ...

function to choose in antd datepicker component

Is there a way to obtain the currently selected date within the onSelect function after updating the selected date in the state? onSelect = (cal) => { this.setState({ selectedValue: cal }); alert(this.state.selectedValue); After making ...

The execution of my code differs between running it locally and in online code editors like CodePen or Plunker

Using jQuery Terminal, I have the following code: function display() { for (var i = 0; i < 100; ++i) { this.echo('line ' + i, { flush: false }); } this.flush(); setTimeout(function() { //thi ...

Guide to developing JavaScript code that moves information from one local website to a different one

Here's the scenario: You input text into a field on website A and click a button. Upon clicking that button, the entered text should appear in website B. I attempted to use localStorage for this functionality, but unfortunately it was not successful. ...