Observing a value in a loop and triggering an asynchronous function using THREE.js

I need to make a function that is asynchronous run when the value changes. It is inside a loop with a determined number of values and the other functions are being executed, but this one, because it has a fontloader, is not working. If the text comes from a file, it shows correctly, but I need to identify the value change (I’m using redux and it’s inside useEffect. Everything that isn’t from the fontloader is working fine), and show the text synchronously. I need this because the input can be via database or via user input. Via fileupload is loading, but does not update with an update (the textloader). Can someone help me?

function AppTextLoader:

const AppTextLoader = (scene: THREE.Scene,  prev_text: string | number, fontsize: number, parent: any, numPhases : number) => {

    const loader = new FontLoader();
    loader.load("gentilis_regular.typeface.json", function (font : any) {   

        const color = '#000000';
        const matDark = new LineBasicMaterial( {  color: color,  side: THREE.DoubleSide  } );

        if(typeof(prev_text)== 'number'){
            prev_text = prev_text.toString();
        }        
        const shapes = font.generateShapes( prev_text, fontsize);
        const geometry = new THREE.ShapeGeometry( shapes );
       
        const text = new THREE.Mesh( geometry, matDark );

        var p = numPhases * 0.33;
       
        var finalposition = new THREE.Vector3(1.3, p, 0);
        finalposition.add(parent.position);
        text.position.copy(finalposition);

        geometry.computeBoundingBox();
        scene.add( text );

    },
    
    );    
};

And here it shows the list. The size varies and each time the number increases, the new list has to be shown. The rest of the drawing (lots of lines) is rendering correctly… except the fontloader

   var tam = 10; //This value comes from the reducer
   for (i = 0; i < tam; i++){
      ... //More objects

      AppTextLoader(scene, text_label_od, od_label_size, myobject, numPhases);

      ... /More objects too
   }


I’m using rjsx which I’m using for something else. Can I use it to solve my problem?

confused-japan

The line between “I use state management libraries to increase productivity and code maintainability” vs “I use state management libraries to confuse the hell out of myself” is thin and too easily crossed. If you still strongly believe you need both redux and rxjs within a single frontend (frontend that I assume is react, while the code above is also 100% imperative) - consider not using either until you realise you need at most one, if at all :smiling_face_with_tear:


  1. Consider stopping using vars. Especially consider stopping using vars together with const and lets - there’s no chance you know what’s defined in which scope and at which point (use only consts, they make code predictable.)
  2. Consider not mixing one_naming_convention with otherOnes - consistency makes debugging easier.
  3. Do not put loaders in useEffect unless you’re 100% sure this useEffect will not run more than once (which already is not truthy when using react in dev mode.) Otherwise there’s a chance you’ll run into race conditions where useEffects call loaders in one order, but the loaders resolve in a different order.
  4. Don’t put logic inside loader callbacks because they are async - loader callbacks should just be responsible for just that - for loading the asset and saving it somewhere. Ie. FontLoader should load font, not create the geometry based on that loaded font.
  5. Consider TTFLoader over FontLoader - it’s simpler, uses the usual font formats which have smaller file size and better support than JSON fonts.
  6. You can go as simple as (is non-react code, so keep in mind, that if you put it inside react lifecycle without modifications it won’t work properly):
const assets = {
  jsonFont: null
};
const queue = [];

new FontLoader().load('...', font => {
  assets.jsonFont = font;

  renderText();
});

const renderText = () => {
  if (!assets.jsonFont || !queue.length) {
    return;
  }

  const queuedText = queue.splice(0);
  queue.length = 0;

  queuedText.forEach(({ text, fontSize, onTextCreated }) => {
    const geometry = new ShapeGeometry(assets.jsonFont.generateShapes(text, fontSize || 1.0));
    const material = new LineBasicMaterial({ color: 0x000000, side: THREE.DoubleSide });
    const mesh = new Mesh(geometry, material);

    onTextCreated(mesh);
  });
};

// NOTE Use this one to create text whenever you feel like it
//            You can also call it within react, just don't declare it there
const updateText = (text, fontSize, onTextCreated = () => {}) => {
  queue.push({
    text,
    fontSize,
    onTextCreated,
  });
  renderText();
};

updateText('random text', 2.0, (mesh) => {
  // NOTE This callback is safely called after both the font asset and the mesh are ready

  mesh.position.set(10.0, 0.0, 0.0);
});

sorry for not knowing. I’m trying to understand. It was already a miracle to know (the basic of) redux and rjsx. I just want you to draw texts using THREE.js… It’s a lot of complication, for something that would theoretically be simple. In fact, who would have thought to automatically draw 3D texts when changing a select? Is my first project, and it seems like I even have to know how all the libraries work to do something.

In that case, I’d definitely throw redux and rxjs away :smiling_face_with_tear: They are an overkill for most projects and can cause a lot of confusion. Take a look at zustand - it’s a super simple alternative (or you can just use useState in React.)

Also worth taking into account that three isn’t too React-friendly - if you’d like to use three.js with React, react-three-fiber will let you do that, taking care of the hard parts for you.

Thanks. I’ve already redid the project four times and one of them I was forced to put async on everything (even the root). Obviously nothing worked. I need to change the values according to user input and the traditional React way (useEffect, useState and Context) didn’t work, because the changes were not made. I got to know RJSX and Redux with chatgpt. I just need to understand and know how to do it, because the examples we see out there are not applicable to complex projects (although, I just want the user to write a text, and a number and THREE copies the text the number of times that was specified) . The other objects respond correctly, except the text.