1
\$\begingroup\$

I'm fairly new to JS and have been learning react this week. Struggling to properly understand the useEffect and useState but think I'm getting there.

I do however think that my use of useRef isn't the right way of doing things and am looking for an experts view on what I have written.

The goal is to write an animated typer that has a human-like feel to the typing with errors etc, while having a fixed rate blinker at the end.

import {useEffect, useRef, useState} from "react";
import parse from 'html-react-parser';

const alp = "abcdefghijklmnopqrstuvwxyz".split("")
const newmin = 25
const newmax = 45

function randomIntFromInterval(min, max) { // min and max included
    return Math.floor(Math.random() * (max - min + 1) + min)
}

function Flasher(flash) {
    const [flashval, updateFlash] = useState("<span>&nbsp&nbsp</span>")
    useEffect(() => {
        if (flash) {
            setTimeout(() => {
                if (flashval === "&nbsp|") {
                    updateFlash("<span>&nbsp&nbsp</span>")
                } else {
                    updateFlash("&nbsp|")
                }
            }, 375)
        }
    })
    return (<>
        {parse(flashval)}
    </>)
}

export default function Typer({text, transform, flash, speed = 1}) {


    const options = useRef(text.split("|"))
    const [display_text, updateTxt] = useState("")
    let index = useRef(0)
    let min = useRef({"now":newmin, "next":newmin})
    let max = useRef({"now":newmax, "next":newmax})

    useEffect(() => {

        //get the full text required
        let current_full_text = options.current[index.current];
        let text_current
        min.current.next = newmin
        max.current.next  = newmax
        //check if should do error or not make error
        if(randomIntFromInterval(1,10)===1){
            text_current = current_full_text.substring(0, display_text.length) + alp[randomIntFromInterval(0, alp.length-1)]
            min.current.next = 120
            max.current.next  = 255
        }else if(display_text !== current_full_text.substring(0, display_text.length)){
            text_current = current_full_text.substring(0, display_text.length-1)
            min.current.next = 60
            max.current.next = 90
        }else{
            //set the current text +1
            text_current = current_full_text.substring(0, display_text.length + 1);
        }

        // logic if need to switch text or not
        if (text_current === current_full_text) {
            // this will wait at the end of each word
            index.current++;
            min.current.now = 300;
            max.current.now  = 400;
            text_current = "";
            // increases the index of the array and if too many then it resets to 0 and reset current text
            if (index.current > options.current.length - 1) {
                index.current = 0;

            }
        }
        setTimeout(() => {
            updateTxt(text_current);
        }, randomIntFromInterval(min.current.now, max.current.now) * 10 * speed)

        min.current.now = min.current.next
        max.current.now = max.current.next
        // ;
    })

    return (<><span>{display_text}</span><Flasher flash/></>)
    //
}

use like this

<Typer speed="0.5" flash={true} text="This is my test typer |I type, therefor I am "/>
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.