Use of the package.json main property when publishing Typescript libraries to NPM

When publishing web components to NPM it’s convenient to use the main property of package.json to publish the bundled module like so.

"main": "build/index.bundle.js",
"module": "build/index.js",
"type": "module",
"types": "build/index.d.ts",

This also makes the bundled API available via the UNPKG CDN.

However I just want to make sure that applications that install the package don’t somehow reference code from the bundle, causing it to be included in the build, instead of from the types / objects / etc that the API exports via index.ts, which has the corresponding javascript version set in the module field.

So is it OK to set the fields like this with respect to using the package in downstream typescript builds?

JavaScript Class related query

In one of my JavaScript basic tasks i am to make a couple of classes and second class will be the first property of first class as an array, how can I manage it correctly?i.e what technique should i use to write this programm?

I can make a simple class but do no know how to add a class as an array to my first class kind of nested class.

Is it possible for someone to track my phone activity using a JavaScript file? [closed]

I found a file named “jquery-2.1.3.min.js” on my Android phone’s internal storage and I think someone I know put it there to track my phone’s browsing history and app browsing history. Is this possible? I’ve since deleted the file and don’t have the code it contained.

After deleting it, it hasn’t come back. It was in the Internal Storage folder on my phone.

How to Create a Horizontally Scrollable Element with Hover Overlay Effect in HTML/CSS?

I’m working on a webpage where I need to create an element with the following properties:

  • Horizontally Scrollable: The element contains multiple dance cards, each representing a dance. It should automatically scroll to the left or right when the mouse is near the left or right edges of the element.
  • Hover Effect: When the mouse hovers over a dance card, the card should increase in size and overlay other elements above it, without changing the layout or spacing of the other elements.

Here’s my current HTML structure:

<div class="horizontal-scroll-videos">
    {% for dance in dances %}
        <a href="/sample/{{ dance.id }}" class="dance-card">
            <div class="dance-card-image-description">
                <img src="{{ dance.image_url }}" class="dance-card-image" alt="{{ dance.name }}">
                <video class="dance-card-video" dance-video-path="{{ dance.video }}" muted></video>
                <p class="dance-card-description body-text">{{ dance.description }}</p>
            </div>
            <div class="dance-card-body">
                <h5 class="dance-card-title">{{ dance.name }}</h5>
                <div class="dance-card-tags">
                    <span class="badge bg-primary">{{ dance.difficulty }}</span>
                    <span class="badge bg-secondary">{{ dance.genre }}</span> 
                    {% if dance.has_instructions %}
                    <span class="badge bg-warning">Tutorial</span> <!-
                    {% endif %}
                </div>
            </div>
        </a>
    {% endfor %}
</div>

I have managed to implement each of these features individually; but problem is that I cannot find a way to have both behaviours functioning at the same time.

I’ve found out that the problem is around the definition of the horizontal-scroll-videos element, particularly about the overflow-x.

.horizontal-scroll-videos {
  display: flex;
  align-items: flex-start;
  gap: var(--inter-video-gap);
  align-self: stretch;
  overflow-x: auto;
  overflow-y: visible;
  scroll-behavior: smooth;
  white-space: nowrap;
  scrollbar-width: none;
}

When overflow-x: auto is enabled: The horizontal scrolling works perfectly. However, the hover effect is cut off, and the dance cards are not able to overlay other elements as desired.

Srolling working but hover not working

When overflow-x: visible is enabled: The hover effect works correctly, and the dance cards overlay other elements as desired. However, the horizontal scrolling functionality is lost.

Hover working but scrolling not working

I have tried to dynamically toggle overflow-x behavior based on user interaction, but the problem is that the scroll loses its position. When switching back to overflow-x: visible, the scroll position resets, and the new content displayed during the scroll is lost.

Code for the hover effect and the scrolling effect is:

function addHoverEffectDanceCards(){
    const danceCards = document.querySelectorAll(".dance-card");
    danceCards.forEach(danceCard => {
        // Get the video and image elements within the dance card
        const video = danceCard.querySelector(".dance-card-video");
        const image = danceCard.querySelector(".dance-card-image");

        // Get the children (the elements within) the dance card
        const children = danceCard.children;
        const childrenArray = Array.from(children);

        childrenArray.forEach(child => {
            // If any element in a dance card gets moused over, add the hover class to every element in the dance card
            child.addEventListener("mouseover", function() {
                const container = danceCard.closest(".horizontal-scroll-videos");
                const containerRect = container.getBoundingClientRect();
                const danceCardRect = danceCard.getBoundingClientRect();
                // Check if the dance card is fully visible within the container; don't show preview if it is not
                if (danceCardRect.left >= containerRect.left && 
                    danceCardRect.right <= containerRect.right) {
                    childrenArray.forEach(child => {
                        classes = child.classList;
                        classes.add("hover");

                        // Add the hover to the children within the dance-card-image-description div
                        if (classes.contains("dance-card-image-description")) {
                            const imgDesChildren = child.children;
                            const imgDesChildrenArray = Array.from(imgDesChildren);

                            imgDesChildrenArray.forEach(imgDesChild => {
                                imgDesChild.classList.add("hover");
                            });
                        };
                    });

                    // Add the hover class to the dance card itself
                    danceCard.classList.add("hover");

                    // Check if the video src for preview is loaded
                    if (!video.src) {
                        // Get the video if it is not defined
                        fetch('/generate_video_url', {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({video_path: video.getAttribute('dance-video-path')})
                        })
                        .then(response => response.json())
                        .then(data => {
                            video.src = data.video_url; // Asign the video
                        })
                        .catch(error => console.error('Error fetching video presigned URL:', error));
                    } 
                    
                    // Start playing the preview
                    video.currentTime = 0;
                    video.play();
                    video.style.display = "block";
                    image.style.display = "none";
                }
            });

            // Remove the hover when no longer mousing over
            child.addEventListener("mouseout", function() {
                childrenArray.forEach(child => {
                    classes = child.classList;
                    classes.remove("hover");

                    // Remove the hover effect from the children inside the dance-card-image-description div
                    if (classes.contains("dance-card-image-description")) {
                        const imgDesChildren = child.children;
                        const imgDesChildrenArray = Array.from(imgDesChildren);
        
                        imgDesChildrenArray.forEach(imgDesChild => {
                            imgDesChild.classList.remove("hover");
                        });
                    };
                });

                // Remove the hover class from the dance card itself
                danceCard.classList.remove("hover");

                // Pause the video and show the image
                video.pause();
                video.style.display = "none";
                image.style.display = "block";
            });
        });
    });

const horizontalScrollContainers = document.querySelectorAll(".horizontal-scroll-videos");

horizontalScrollContainers.forEach(container => {
    let scrollInterval;

    container.addEventListener('mouseover', (e) => {
        const screenWidth = window.innerWidth;
        const scrollThreshold = 200;
        // Check if mouse is within the scrollThreshold from the right edge
        const checkLeftScroll = (e) => {
            const mouseX = e.clientX;
            return mouseX > screenWidth - scrollThreshold;
        };
        const checkRightScroll = (e) => {
            const mouseX = e.clientX;
            return mouseX < scrollThreshold;
        }
        if (checkLeftScroll(e)) {
            scrollInterval = setInterval(() => {container.scrollLeft += 180;}, 30);
        } else if (checkRightScroll(e)) {
            scrollInterval = setInterval(() => {container.scrollLeft -= 180;}, 30);
        }
    });

    container.addEventListener('mouseout', () => {
        clearInterval(scrollInterval);
        scrollInterval = null;
    });
});

I am a beginner in this field, and any help or suggestions on how to achieve this would be greatly appreciated!

How do I use sweetalert on each item in an array?

I’m trying to use JQuery to loop over an array of strings, and for each item use sweetalert1.0 to prompt the user with a confirm and cancel button. I’m only getting one sweetalert prompt for the last item in the array. Below is the code I’ve tried. It only shows swal() for letter “C” and not “A” or “B”. Can someone please help?

let array_letters = ["A", "B", "C"];

$.each(array_letters, function (i, letter) {
    swal({
         title: "Print " + swal_title + "?",
         type: "warning",
         closeOnConfirm: true,
         showConfirmButton: true,
         confirmButtonText: "Yes",
         showCancelButton: true,
     });
});

How to programmatically scroll up conversation in WhatsApp web

Please, how to create a script which would programmatically scroll up conversation in WhatsApp web, up to the very start. Doing it manually is excruciatingly slow and dull.
I was thinking about using Puppeteer, whatsapp-web.js or Greasemonkey/ Tampermonkey.

Background:

The best way to backup WhatApp conversation I found so far is to use WhatsApp Web and manually scroll to the beginning and then use SingleFile (browser extension) to store it as HTML. It works like a charm – it preserves the original chat look, it include image thumbnails and is essentially without limit how far you can go, no backup message limit.
I saved conversations like this that were kilometres long 🙂
Result is one neat HTML file, searchable and good looking.

Challenges:

  • WhatsApp needs to be logged in. After first successful login WhatsApp rememberers you (cookies?) and automatically opens the app. So this should not be a problem.
  • Opening correct conversation – I can do this manually.
  • The conversation is in a div with scrollable overflow.
  • The script should basically emulate mouse scrolling over that div.
  • It cannot be done too aggressively to avoid potential ban (??).

Puppeteer – looks like a lot of work and I’m unfortunately a skilled JS developer; I’m a Java developer. Puppeteer seems to be used mainly for UI testing.
I’m not sure if I can use Puppeteer on already opened page.

whatsapp-web.js is a high level API, which I like; it is based on Puppeteer, but it’s intended mainly for bots. It has API methods like fetchMessages(), which return only text, but not methods for scrolling conversation up.

Greasemonkey/Tampermonkey – I have no experience; they look like my best bet.

I appreciate solution in any of those above. The simpler the better.

Error related to pdf.worker.min says ‘import’, and ‘export’ cannot be used outside of module code

I am getting this error when pushing a build to Vercel:

Failed to compile.
static/media/pdf.worker.min.50acc843.mjs from Terser
  x 'import', and 'export' cannot be used outside of module code
    ,-[18:1]
 18 |  *
 19 |  * @licend The above is the entire license notice for the
 20 |  * JavaScript code in this page
    :                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
    `----
Caused by:
    0: failed to parse input file
    1: Syntax Error
Error: 
  x 'import', and 'export' cannot be used outside of module code
    ,-[18:1]

I tried reading here, here, here and here, but couldn’t find a solution that worked for me. So basically it is somehow related to pdfjs or pdf-lib, because after installing them, it has occur.

I am using pdf-lib version 1.17.1 and pdfjs-dist version 4.5.136 (according to package.json)

This is how I use them in my code:

import { PDFDocument } from 'pdf-lib';
import * as pdfjsLib from 'pdfjs-dist';

// Polyfill for Promise.withResolvers
if (typeof Promise.withResolvers === 'undefined') {
  (Promise as any).withResolvers = function () {
    let resolve: (value: unknown) => void;
    let reject: (reason?: any) => void;
    const promise = new Promise((res, rej) => {
      resolve = res;
      reject = rej;
    });
    return { promise, resolve: resolve!, reject: reject! };
  };
}

pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
  'pdfjs-dist/legacy/build/pdf.worker.min.mjs',
  import.meta.url
).toString();

Testing a method in a Vue3 setup component with vitest

I need to make a test for a method in a VUE3 setup in a component and nothing I have tried works.

Here is the simplified component:

<script setup>

function myFunction(number) {
   return number + 1
}

</script>

<template>
// code here

And the test:

import { MyComponent } from '@/Components/MyComponent.vue'
import { describe, expect, test } from 'vitest'
import { mount } from '@vue/test-utils'

describe('MyComponent.vue', () => {

    test('myMethodWorks', () => {
        const wrapper = mount(MyComponent)
        const result = wrapper.vm.$setupState.myFunction(1);
        expect(result).toBe(2)
        
    });
});

But I keep getting the error: ReferenceError: document is not defined. There are other tests in the Vue test folder that work fine, so I shouldn’t need to change any config files. But none of the other tests are trying to test a method from a Vue3 component.
Even if I put in the test :
expect(true).toBe(true)
I still get the same error.

What am I doing wrong?

Can I track when the user clicks the close app button?

I need to understand when the user closes the application and check the data in the database before that. Is it possible to track when he clicks on the button to close the app?

And is it possible to perform any requests to the database before it closes the application, for example closes Telegram with a swipe?

I tried to track this event but I don’t get it.

Culling polygons which are behind the camera

This question is deeply related to Z-Clipping / Depth-Clipping in a Javascript 3D Engine. I have an issue of where if a polygon is meant to be behind the camera it will still render, covering the screen because its z position is equal to 0.1 (no polygons behind camera issue). Can you replace/recode the function(s) which need to be? Here is the demo replit link: replit.com/js-3d-2.

I tried to see if all of the vertices z position is 0.1 (the result of no verts behind camera) and if so culling the polygon. It didn’t work.

How to Convert GeoJSON Points and Polygons to 3D Objects using Three.js in JavaScript?

I am working on a project where I need to convert GeoJSON data into 3D objects using Three.js in JavaScript. My GeoJSON data contains two types of features: points and polygons. I want to render these features in a 3D environment, where points are represented as spheres and polygons are represented as extruded shapes.

Here is an example of the GeoJSON data format I am working with:

"type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [coords x,y]
          ]
        ]
      },
      "properties": {
        "name": "Polygon A"

What I Have Tried
I have set up a basic Three.js scene, but I am having trouble converting the GeoJSON data into 3D objects. Here is the code I have so far:

function processGeoJSONData(data) {
    console.log(data);

    const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); 
    data.features.forEach(feature => {
        console.log("feature::", feature);
        if (feature.geometry.type === 'Point') {
            console.log("point feature:", feature.geometry);
            const [x, y, z] = feature.geometry.coordinates;
            const geometry = new THREE.BoxGeometry(1, 1, 1); 
            const box = new THREE.Mesh(geometry, material);
            box.position.set(x, y, z);
            scene.add(box);
        } else if (feature.geometry.type === 'Polygon') {
            console.log("polygon feature:", feature.geometry);
        }
    });
}

fetch('data/coordinates.geojson')
    .then(response => response.json())
    .then(data => {
        processGeoJSONData(data);
    })
    .catch(error => console.error(error));

What I Need Help With
Points:
How can I convert GeoJSON points into Three.js spheres and add them to the scene?
Polygons: How can I convert GeoJSON polygons into Three.js extruded shapes and add them to the scene?
General Advice: Any general advice or best practices for working with GeoJSON data and Three.js?

What I Expect
I would appreciate detailed guidance on how to achieve the conversion and rendering of both points and polygons. If possible, please provide code snippets or examples that demonstrate the solution.

Thank you in advance for your help!`

Bugging at rescale() function in D3js

i’m working on a data visualize project and trying to use D3js library for graphs. Everything is fine, except when I try to let my bar chart zoomable on X scale.

<div class="row" id="bar-chart-append">
              <div class="container" style="margin: 20px; margin-top: 0px">
                <input type="number" id="numofservice" placeholder="Number of service providers" class="col-3" step="10" min="0">
                <select id="select-order" class="col-8">
                  <h6 class="dropdown-item-text">Order</h6>
                  <option value="alphabetical">Alphabetical</option>
                  <option value="ascending">TFT Score, ascending</option>
                  <option value="descending" selected>TFT Score, descending</option>
                </select>
              </div>
            <div id="tooltip2" class="tooltip bs-tooltip-bottom"></div>
          </div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3.min.js"></script>
<script src="/js/graph/graphs.js"></script>

graphs.js:

const numOfService = document.getElementById('numofservice');
const barChartAppend = document.getElementById('bar-chart-append');
numOfService.addEventListener('change', async function() {
        const value = numOfService.value;
        if (!isNaN(value) && value.trim() !== '') {
            data2 = await fetch(`/api/topUser?n=${value}`).then(response => response.json());
            barChartAppend.removeChild(barChartSVG);
            barChartSVG = barChart(data2, barChartAppend.clientWidth, barChartAppend.clientHeight);
            barChartAppend.append(barChartSVG);

        } else {
            console.log('The value is not a number:', value);
        }
    });
$(document).ready(function() {
        $('.selectpicker').selectpicker();
        $('#select-order').on('changed.bs.select', function(e, clickedIndex, isSelected, previousValue) {
            console.log('Selected value:', $(this).val());
            switch ($(this).val()) {
                case 'alphabetical':
                    barChartSVG.update((a, b) => a.owner.localeCompare(b.owner));
                    break;
                case 'ascending':
                    barChartSVG.update((a, b) => a.first_combine - b.first_combine);
                    break;
                case 'descending':
                    barChartSVG.update((a, b) => b.first_combine - a.first_combine);
                    break;
            }
        });
    });
window.onload = async function() {
    var data2 = await fetch('/api/topUser?n=10').then(response => response.json());
    var barChartSVG = barChart(data2, barChartAppend.clientWidth, barChartAppend.clientHeight);
    barChartAppend.append(barChartSVG);
}
function barChart(data2, parentWidth = 1200, parentHeight = 400) {
    // Specify the chart’s dimensions.
    const width = parentWidth;
    const height = Math.min(parentHeight, width / 3);
    const marginTop = 20;
    const marginRight = 0;
    const marginBottom = 30;
    const marginLeft = 40;
    const barColor = "#ff8c00";

    // Declare the x (horizontal position) scale and the corresponding axis generator.
    const x = d3.scaleBand()
        .domain(data2.map(d => d.owner))
        .range([marginLeft, width - marginRight])
        .padding(0.1);

    const xAxis = d3.axisBottom(x).tickSizeOuter(0);

    // Declare the y (vertical position) scale.
    const y = d3.scaleLinear()
        .domain([0, d3.max(data2, d => d.first_combine)]).nice()
        .range([height - marginBottom, marginTop]);

    // Create the SVG container.
    const svg = d3.create("svg")
        .attr("viewBox", [0, 0, width, height])
        .attr("style", `max-width: ${width}px; height: auto; font: 10px rubik; overflow: visible;`)
        .attr("width", width)
        .attr("height", height);

    const barsGroup = svg.append("g").attr("class", "bars");

    const bar = barsGroup.selectAll("rect")
        .data(data2)
        .join("rect")
        .attr("fill", barColor) // Default color of the bars.
        .attr("x", d => x(d.owner))
        .attr("y", d => y(d.first_combine))
        .attr("height", d => y(0) - y(d.first_combine))
        .attr("width", x.bandwidth())
        .on("mouseover", function(event, d) {
            d3.select('#tooltip2').html(nodeDetail(d)).style("visibility", "visible").style("opacity", 1);
            d3.select(this)
                .attr("fill", shadeColor(barColor, -15));
        })
        .on("click", function(event, d) {
            window.open(`/profile?owner=${d.owner}`, '_blank');
        })
        .on("mousemove", function(event, d) {
            d3.select('#tooltip2')
                .style("top", (event.pageY - 10) + "px")
                .style("left", (event.pageX + 10) + "px");
        })
        .on("mouseout", function() {
            d3.select('#tooltip2').html(``).style("visibility", "hidden").style("opacity", 0);
            d3.select(this).attr("fill", barColor);
        });

    // Create the axes.
    const gx = svg.append("g")
        .attr("class", "x-axis")
        .attr("transform", `translate(0,${height - marginBottom})`)
        .call(xAxis);

    const gy = svg.append("g")
        .attr("class", "y-axis")
        .attr("transform", `translate(${marginLeft},0)`)
        .call(d3.axisLeft(y).tickFormat(y => y))
        .call(g => g.append("text")
            .attr("x", -marginLeft)
            .attr("y", 0)
            .attr("fill", "currentColor")
            .attr("text-anchor", "start")
            .text("↑ TFT Score"))
        .call(g => g.select(".domain").remove());

     function zoomed(event) {
        console.log('Zoom event:', event);
        console.log('Transform:', event.transform);
        console.log('X scale:', x);
        const transform = event.transform;
        const newX = transform.rescaleX(x);
        console.log('New X scale:', newX);
        gx.call(d3.axisBottom(newX).tickSizeOuter(0));
        barsGroup.selectAll("rect")
            .attr("x", d => newX(d.owner))
            .attr("width", newX.bandwidth());
    }

    svg.call(d3.zoom()
        .scaleExtent([1, 8])
        .translateExtent([[0, 0], [width, height]])
        .extent([[0, 0], [width, height]])
        .on("zoom", zoomed));

    // Return the chart, with an update function that takes as input a domain
    // comparator and transitions the x axis and bar positions accordingly.
    return Object.assign(svg.node(), {
        update(order) {
            x.domain(data2.sort(order).map(d => d.owner));

            const t = svg.transition()
                .duration(750);

            bar.data(data2, d => d.owner)
                .order()
                .transition(t)
                .delay((d, i) => i * 20)
                .attr("x", d => x(d.owner));

            gx.transition(t)
                .call(xAxis)
                .selectAll(".tick")
                .delay((d, i) => i * 20);
        }
    });
}

The data2 will be an array of json objects like [{"owner" : "Mei","id" : "1234","group" : ["service_provider"],"first_combine":100,"properties" : {}}]

Everytime I try to call the zoomed() function, it throws an exception:

Uncaught TypeError: undefined is not a function
    at Array.map (<anonymous>)
    at rescaleX (graphs.js:476:28)
    at SVGSVGElement.zoomed (graphs.js:481:22)
    at Dt.call (d3.min.js:2:15713)
    at M.emit (d3.min.js:2:278459)
    at M.zoom (d3.min.js:2:278301)
    at SVGSVGElement.T (d3.min.js:2:274295)
    at SVGSVGElement.<anonymous> (d3.min.js:2:20686)

These console.log() line will return:

Zoom event: xw {type: 'zoom', sourceEvent: WheelEvent, transform: ww, _: Dt, target: ƒ}
Transform: ww {k: 1.9042067625774186, x: -233.285344744974, y: -176.10556683706443}
X scale: ƒ i(i){let o=t.get(i);if(void 0===o){if(r!==pg)return r;t.set(i,o=n.push(i)-1)}return e[o%e.length]}

I think X scale is bugging but I don’t know how to fix that. Is there anyone can help me with that problem?

Warning: TouchableHighlight is accessing findNodeHandle inside its render() in React Native – How to resolve?

I’m working on a React Native app and I’ve encountered a warning that I’m having trouble resolving. The warning message is:

Warning: TouchableHighlight is accessing findNodeHandle inside its render(). render() should be a pure function of props and state. It should never access something that requires stale data from the previous render, such as refs. Move this logic to componentDidMount and componentDidUpdate instead.
in TouchableHighlight (created by TouchableHighlight)

The warning indicates that TouchableHighlight is accessing findNodeHandle inside its render() method, and it suggests moving this logic to componentDidMount or componentDidUpdate. However, I am using functional components with React Hooks and would like to avoid the use of lifecycle methods like componentDidMount and componentDidUpdate.

How can I move the logic that uses findNodeHandle from the render phase to a different part of a functional component using hooks?
Is there a better way to handle such operations in React Native with functional components to avoid warnings?
I would greatly appreciate any suggestions or solutions to this issue using hooks. Thanks in advance for your help!

import React, {useState, useRef, forwardRef} from 'react';
import {TouchableHighlight, View} from 'react-native';

const FocusableHighlight = forwardRef((props, ref) => {
  const [focused, setFocused] = useState(false);
  const [pressed, setPressed] = useState(false);

  return (
    <TouchableHighlight
      {...props}
      ref={ref}
      delayLongPress={500}
      onLongPress={(event) => {
        console.log('long press: ' + props.nativeID)
        if (props.onLongPress) {

          props.onLongPress(event);
        }

      }}
      onPress={(event) => {


          setPressed(parseInt(event.eventKeyAction) === 0);
          if (props.onPress) {
            props.onPress(event);
          }
        
      }}
      onFocus={(event) => {
        console.log('focus: ' + props.nativeID);
        setFocused(true); 
        if (props.onFocus) {
          props.onFocus(event);
        }
      }}
      onBlur={(event) => {
        setFocused(false);
        if (props.onBlur) {
          props.onBlur(event);
        }
      }}
      style={[
        props.style,
        focused && {
          backgroundColor: props.underlayColor,
          opacity: props.activeOpacity,
        },
        focused && props.styleFocused,
        pressed && props.stylePressed,
      ]}>
      {props.children || <View />}
    </TouchableHighlight>
  );
});

export default FocusableHighlight;

Problem in Redux Toolkit’s Async Thunks: State Not Properly Updated in React Component After Actions Are Dispatched

I am working on a React application where I use Redux Toolkit for state management. I have a complex setup where I’m dispatching an async thunk to fetch data from a Node.js backend. Data fetching is performed correctly, but there’s a problem whereby it doesn’t update properly in the state of the component after dispatch.

I’m sending an async thunk for fetching user details inside my React component. The data gets fetched correctly, but somehow, the component doesn’t seem to re-render with a newly updated state. I can confirm that in Redux, the state does get updated, but somehow it doesn’t reach my component.

Question

Why is my React component not re-rendering when the state changes in Redux, although the state in Redux DevTools does show the correct data? Possibly what I am missing in this setup? Any help or guidelines on how to debug much appreciated!

Redux Slice:

// userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';

export const fetchUserDetails = createAsyncThunk(
  'user/fetchUserDetails',
   async (userId) => {
     const response = await axios.get(`/api/users/${userId}`);
     return response.data;
   }
);

const userSlice = createSlice({
   name: 'user',
   initialState: {
   userDetails: {},
   status: 'idle',
   error: null,
},
reducers: {},
    extraReducers: (builder) => {
        builder
        .addCase(fetchUserDetails.pending, (state) => {
            state.status = 'loading';
        })
        .addCase(fetchUserDetails.fulfilled, (state, action) => {
            state.status = 'succeeded';
            state.userDetails = action.payload;
        })
        .addCase(fetchUserDetails.rejected, (state, action) => {
            state.status = 'failed';
            state.error = action.error.message;
        });
    },
});

export default userSlice.reducer;

React Component:

// UserProfile.jsx
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUserDetails } from '../slices/userSlice';

const UserProfile = ({ userId }) => {
  const dispatch = useDispatch();
  const { userDetails, status, error } = useSelector((state) => state.user);

  useEffect(() => {
    if (status === 'idle') {
      dispatch(fetchUserDetails(userId));
    }
  }, [dispatch, userId, status]);

  if (status === 'loading') {
      return <div>Loading...</div>;
  }

  if (status === 'failed') {
    return <div>Error: {error}</div>;
  }

  return (
    <div>
      <h1>{userDetails.name}</h1>
      <p>Email: {userDetails.email}</p>
    </div>
  );
};

export default UserProfile;
  • The state in Redux DevTools is updating properly when the async thunk is being fulfilled.

  • It properly selects the state from the Redux store using the useSelector hook.

  • The useEffect dependencies have been confirmed to include all the necessary ones: dispatch, userId, status.

Switching users in tic tac toe game

I am currently working on tic tac toe project with javascript html css.
The problem is I did set the constructors by the input of the user but
I cannot switch over the user when I play my game

My expectations are be able to switch user when you play your turn.
I tried if else by assigning currentplayer to player 1 if player 1 – I want to change it to player2

const gameBoard = (function() {
  // Select DOM elements
  const playerInput1 = document.querySelector("#player-select1");
  const playerButton = document.querySelector(".add-player");
  const playerInput2 = document.querySelector("#player-select2");
  const playerPara1 = document.querySelector(".player1");
  const playerPara2 = document.querySelector(".player2");
  const showPlayers = document.querySelector(".player-shows");
  const boxes = document.querySelectorAll(".box");

  // Game markers
  const gameMarker = ["O", "X"];
  let currentPlayer;
  let player1, player2;

  // Player factory function
  const playerSelection = (name, marker) => {
    let score = 0;
    return {
      name,
      marker,
      getScore: function() {
        return score;
      },
      scorePlus: function() {
        score++;
        return score;
      }
    };
  };

  // Initialize players
  player1 = playerSelection("Name", gameMarker[0]);
  player2 = playerSelection("Name", gameMarker[1]);

  // Event listener for player names
  playerButton.addEventListener("click", () => {
    player2.name = playerInput2.value.trim();
    player1.name = playerInput1.value.trim();

    if (player1.name === "" || player2.name === "") {
      alert("Please enter a name");
    } else {
      playerPara1.textContent = `First Player is: ${player1.name} (${player1.marker})`;
      playerPara2.textContent = `Second Player is: ${player2.name} (${player2.marker})`;
      showPlayers.innerHTML = "";
      showPlayers.append(playerPara1);
      showPlayers.append(playerPara2);

      // Start the game by setting the initial player
      playGame();
    }
  });

  // Add event listeners to boxes
  boxes.forEach((element) => {
    element.addEventListener("click", () => {
      if (element.textContent === "" && currentPlayer) { // Ensure box is empty and a player is set
        element.textContent = currentPlayer.marker; // Mark the box with the current player's marker
        playGame(); // Switch to the next player
      }
    });
  });

  // Function to switch current player
  const playGame = () => {
    if (currentPlayer === player1) {
      player1
    } else if (currentPlayer === player2) {
      player2
    }


  };

  // Return public methods
  return {
    playerSelection,
    playGame
  };
})();
<input type="text" id="player-select1">
<buttton class="add-player">Add</button>
<input type="text" id="player-select2">
<p class="player1"></p>
<p class="player2"></p>

<div class="player-shows"></div>

<div id="board">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<br>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<br>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<br>
</div>