Quick React 4 Hooks State Machine

Posted on October 2, 2021
Tags: javascript

1 summary

Concept Producer Consumer Description
State setState getState Obvious
Context const MyContext = createContext(null) <MyContext.Provider ...> Only by creating the Context can we create the Context Provider JSX element
Context <MyContext.Provider value={}/> specifically the value const myService = useContext(MyContext) Only by setting the value in the Context Provider, are we allowed to use the value via useContext (THIS GETS ENHANCED BY XSTATE useActor)
Context setState(stuff) <MyContext.Provider value={{getState()}}/> context’s value is both a producer and a consumer. (THIS GETS OBSOLETED BY XSTATE useInterpret)
Concept Producer Consumer Description
XState const authService = useInterpret(authMachine); <MyContext.Provider value={{authService}}/> useInterpret is the alternative to <MyContext.Provider value={{getState()}} since it prevents needless rerenders
XState const myService = useContext(MyContext) const [bleh] = useActor(myService.data) enchanced from useContext

2 xState keywords

import { Machine, assign, createMachine, interpret,  } from "xstate";

const QueueMachine = createMachine(
{
/** @xstate-layout N4IgpgJg5mDOIC5QEUCuZ0DoCyB5AcrgJIAiAxAAoCqAygBIDaADALqKgAOA9rAJYAuvLgDt2IAB6IAtAGYArE0wAOJgCZVAdgAsSnTIBscgIwAaEAE9ERo1sxHVTfUofqmBtQF8PZtBjA4CYnIKXApmNiQQbj5BETFJBFkFZTVNHT1DUwtEVSMlZTklfXkNVSV5GS8fdCw8QlJMQnwAUWwKABUATTJwsWiBIVFIhKYzSwQmKpBfWsCG1o7u3sj+2KHQBKkjRS0ZbQBODW3cpX2VfbGrff3MLTUZXZkZazkZMq9vEGEuCDgxGbAfR4Aziw2kMjOKXU2l05Uyl0SRm0mGuqP2TAxckOGg0UwBAXqJCBMUG8WkNiMmAxTCR9n09O0GgRUiUGluaP2CjUZyUSjxNX8dSCjQICy6xJB6wkViRmAccgUr30THSWiZ2QQ9nyuS0r1Uh3puyYfM++KF8za4pWwLWZMS+xkVIxtNU9P0jIR1huWn2RkK5TKNNKHw8QA */
  id: "Queue",
  predictableActionArguments: true,
  initial: "MONOID",
  context: {
    count: 0,
    data: [],
  },
  states:{
    MONOID : {
      initial: "EMPTY",

      states: {
          NONEMPTY:{
            
              always:[{
                target: "EMPTY",
              cond: "isEmptyCond",
            actions: (context,event) => console.log("rfe")}] 
            
          },
          EMPTY:{
            always:[{
              target: "NONEMPTY",
            cond: "isNotEmptyCond",
          actions: (context,event) =>  console.log("ahh")}] 
          
          }
      },

      on: {
        PUSH: {
          target: "MONOID",
          internal: true,
        //   actions: (context,event) => assign({count: context.count + 1})
          actions: assign({
            count: (context,event) => {return context.count + 1; },
            data: (context,event) => {return context.data.concat(event.data);},
          })
        },

        POP: {
          target: "MONOID",
          internal: true,
          actions: assign({
            count: (context,event) =>  {return context.count - 1},
            data: (context,event) => {return context.data.slice(1)},
          })
        }
      }
    }

  }},
  {
  
    guards: {
        isEmptyCond: (context,event)=> {return (context.count == 0)},
        isNotEmptyCond: (context,event)=> {return (context.count != 0)}
  
      }
    }
    
)



class MyQueue{
  bleh = interpret(QueueMachine);
  constructor(myarray){
    this.bleh.onTransition((state) => console.log(state.value)).start()
    myarray.forEach(element => {
      this.bleh.send("PUSH",{data: element});
    });
  };
  push(newdata){
    this.bleh.send("PUSH",{data: newdata})
    return this.bleh.getSnapshot().context.data
  }
  pop(){
    if(this.bleh.getSnapshot().matches({"MONOID": "NONEMPTY"})){
      let toReturn = this.bleh.getSnapshot().context.data[0];
      this.bleh.send("POP")
      return toReturn
    } 
    else if(this.bleh.getSnapshot().matches({"MONOID": "EMPTY"})){
      return null
    }
  }
  len(){
    return this.bleh.getSnapshot().apply().context.count
  }
  log(){
    console.log(this.bleh.getSnapshot().context, this.bleh.getSnapshot().toStrings())
    return
  }

}



// bleh.send("PUSH",{data: "shit"})
// bleh.send("PUSH",{data: "crap"})
// bleh.send("POP")
// bleh.send("isEmpty")
// bleh.send("isEmpty")
// console.log(bleh.getSnapshot().nextEvents)
// console.log(bleh.getSnapshot().context)


const bbb = new MyQueue([])
bbb.push(3)
// console.log(bbb.bleh.getSnapshot().context)
bbb.push(5)
bbb.pop()
bbb.pop()
console.log(bbb.bleh.getSnapshot().matches({MONOID: "EMPTY"}))
console.log(bbb.pop())
console.log(bbb.pop())
bbb.log()
// console.log(bbb.bleh.getSnapshot().nextEvents)
// const vvv = new MyQueue([3,5,6,7]);
// console.log(bbb.pop())
// console.log(bbb.push(95))
// console.log(bbb.pop())
id: 'bleh',
initial: 'hereitbegins',
context: {
  GLOBALSTUFF: undefined,
  MYCONFIGS: {},
  },
states: {
  
}

3 useMemo

import "./styles.css";
import React, {useMemo,useState,useEffect} from 'react';
const slowfunction = (num) => {
  console.log("slow function");
  for(let i = 0 ; i <= 10000000; i++){};
  return num * 2;   
}

export default function App() {
  const [count,setCount] = useState(0);
  const [count2,setCount2] = useState(0);
  const memoizedslowfunction = useMemo(() => {
    return slowfunction(count)
  },[count]);

 
  return (
    
    <div className="App">
      
      <button onClick = {event => {
        setCount(cstate => cstate + 1)
        }}>Not Often pressed button</button>
        <p>Not Often Updated Value: {slowfunction(count)}</p>
        <p>Above count value needs to be memoized</p>
      <h2>----------</h2>


      <button onClick = {event => {
        setCount2(cstate => cstate + 1)
      }}>Often pressed button</button>
      <p>Often Updated Value: {count2}</p>
    </div>
  );
  }

4 Adapting external libraries into JS

const mygraph = new Graph({multi: true});
mygraph.import(graphdata) 
const settingsSigma = { labelRenderedSizeThreshold: 1,}
const mydiv = document.getElementById("mydiv");
new Sigma(mydiv,mygraph,settings);
const MyComponent = () => {
    const myDiv = useRef(null);
    let hoveredEdge = null;
    useEffect(()=>{
        const mygraph = new Graph({multi: true});
        mygraph.import(graphdata) 
        const settingsSigma = { labelRenderedSizeThreshold: 1,}
        const renderer = new Sigma(mygraph,myDiv.current,settingsSigma);
        return () => {//disposal - or else if you resize, you get duplicate graphs
            renderer.kill()
        }
    },[])
    return(
        <>
        <div ref={myDiv} style={{"height" : "100vh", "width" : "50%"}}></div>
        
        </>
    )
}