es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo refactorizar una clase como un hook para gestionar una pila en React?

Necesito una pila para gestionar los estados de algunas etiquetas. Al principio, las declaro como ref de esta manera: const stack = React.useRef([]), const index = React.useRef(0), y visito la pila y la mantengo manualmente.

Después de eso, intento abstraerlos como una clase independiente:

import { Label } from '../interface/basic'
import { groupBy } from '../utils/categorys&colors'

export interface Can {
  redo: boolean
  undo: boolean
  reset: boolean
  save: boolean
}

export interface State extends Array<Label> {}

export class StateStack {
  private stateStack: State[] = []
  private index: number = 0
  can: Can

  constructor(initialState?: State) {
    if (initialState) {
      this.stateStack.push(initialState)
      this.index = 1
    }
    this.updateCan()
  }

  reset() {
    this.stateStack = []
    this.index = 0
    this.updateCan()
    return this
  }

  nowState() {
    this.updateCan()
    return this.stateStack[this.index - 1]
  }

  nextState() {
    this.index += this.can.redo ? 1 : 0
    return this.nowState()
  }

  prevState() {
    this.index -= this.can.undo ? 1 : 0
    return this.nowState()
  }

  resetState() {
    if (this.can.reset)
      this.index = this.index !== 1 ? 1 : this.stateStack.length
    return this.nowState()
  }

  pushState(newState: State) {
    this.stateStack = this.stateStack.slice(0, this.index)
    this.index = this.stateStack.push(newState)
    return this.nowState()
  }

  updateCan() {
    this.can = {
      redo: this.index < this.stateStack.length,
      undo: this.index > 1,
      reset: this.stateStack.length > 1,
      save: this.index > 1 || this.index < this.stateStack.length
    }
  }

  groupedState() {
    return this.nowState() ? groupBy(this.nowState(), 'categoryName') : {}
  }
}

Luego declaro un estado en la capa superior de esta manera: const stateStack = useState(new StateStack()). En su mayoría, funciona bien, pero tiene algunos problemas pequeños de volver a renderizar.

Así que intenté refactorizarlo como un hook pero fracasé. ¿Alguien puede ayudarme a reconstruir esta clase?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Claro, puedo ayudarte a refactorizar la clase StateStack en un hook de React.

    Aquí tienes el código refactorizado:

    import { useState, useEffect } from 'react';
    import { Label } from '../interface/basic';
    import { groupBy } from '../utils/categorys&colors';
    
    export interface Can {
      redo: boolean;
      undo: boolean;
      reset: boolean;
      save: boolean;
    }
    
    export interface State extends Array<label> {}
    
    export function useStateStack(initialState?: State) {
      const [stateStack, setStateStack] = useState<state[]>(initialState ? [initialState] : []);
      const [index, setIndex] = useState(initialState ? 1 : 0);
      const [can, setCan] = useState<can>({ redo: false, undo: false, reset: false, save: false });
    
      function reset() {
        setStateStack([]);
        setIndex(0);
      }
    
      function nowState() {
        updateCan();
        return stateStack[index - 1];
      }
    
      function nextState() {
        setIndex(prevIndex => prevIndex + (can.redo ? 1 : 0));
        return nowState();
      }
    
      function prevState() {
        setIndex(prevIndex => prevIndex - (can.undo ? 1 : 0));
        return nowState();
      }
    
      function resetState() {
        if (can.reset) setIndex(prevIndex => (prevIndex !== 1 ? 1 : stateStack.length));
        return nowState();
      }
    
      function pushState(newState: State) {
        setStateStack(prevStateStack => prevStateStack.slice(0, index).concat(newState));
        setIndex(prevIndex => prevStateStack.length + 1);
        return nowState();
      }
    
      function updateCan() {
        setCan({
          redo: index < stateStack.length,
          undo: index > 1,
          reset: stateStack.length > 1,
          save: index > 1 || index < stateStack.length,
        });
      }
    
      function groupedState() {
        return nowState() ? groupBy(nowState(), 'categoryName') : {};
      }
    
      useEffect(() => {
        updateCan();
      }, [index]);
    
      return {
        stateStack,
        index,
        can,
        reset,
        nowState,
        nextState,
        prevState,
        resetState,
        pushState,
        groupedState,
      };
    }
    

    Para usar el hook useStateStack, simplemente puedes llamarlo como una función:

    import { useStateStack } from './tu-carpeta-de-hooks';
    
    function MyComponent() {
      const { stateStack, index, can, reset, nowState, nextState, prevState, resetState, pushState, groupedState } =
        useStateStack();
    
      // tu código de componente...
    }
    

    Espero que esto te sea de ayuda. Avísame si tienes alguna pregunta.</state[]>

Comments are closed.