Rooks
State Management

useStackState

Manages stack (LIFO) state with push, pop, and peek operations.

About

A React hook that manages state in the form of a stack

Examples

Basic usage

import React, { useRef } from "react";
import "./styles.css";
import { AnimatePresence, motion } from "framer-motion";
import { useStackState } from "rooks";
import styled from "styled-components";

const variants = {
  appear: {
    opacity: 0,
    y: "-150%",
    x: "-15%",
    rotate: -15,
    transition: {
      duration: 0.5,
    },
  },
  disappear: {
    opacity: 0,
    y: "-200%",
    x: "100%",
    rotate: 45,
    transition: {
      duration: 0.5,
    },
  },
  visible: {
    opacity: 1,
    y: "0%",
    x: "0%",
    rotate: 0,
    transition: {
      duration: 0.5,
    },
  },
};

const StackInner = styled(motion.div)`
  border-bottom: 5px solid black;
  padding: 0 12px 3px;
  width: 300px;
  > * {
    margin: 0;
    padding: 12px 16px;
  }
`;

export function StackDiv({ children, ...props }) {
  return (
    <StackInner {...props}>
      <AnimatePresence initial={false}>{children}</AnimatePresence>
    </StackInner>
  );
}

export const StackItem = styled(motion.div).attrs((props) => ({
  variants,
  initial: "appear",
  animate: "visible",
  exit: "disappear",
}))`
  width: 100%;
  background-color: rgba(254, 243, 199, 1);
  margin: 0;
  padding: 12px 16px;
  font-weight: 500;
  font-size: 1rem;
  line-height: 1.5rem;
  border-color: rgba(0, 0, 0, 1);
  border-width: 1px;
  border-style: solid;
  border-radius: 0.375rem;
  place-content: center;
  display: flex;
`;

export const ActionButton = styled(motion.button)`
    width: 100%;
  font-weight: 500;
  color: rgba(67,56,202,1);
  font-size: 1rem;
  line-height: 1.5rem;
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  border-color: transparent;
  align-items: center;
  display: inline-flex;
  border-radius: 0.375rem;
  border-color: transparent;
  background-color: rgba(224,231,255,1);
}
`;

export const ActionButton2 = styled(motion.button)`
  width: 100%;
  font-weight: 500;
  font-size: 1rem;
  line-height: 1.5rem;
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  border-color: transparent;
  align-items: center;
  display: inline-flex;
  border-radius: 0.375rem;
  border-color: transparent;
  background-color: rgba(254, 226, 226, 1);
`;

export const ActionButtons = styled.div`
  margin: 12px 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 16px;
`;

export const Root = styled.div`
  height: 100vh;
  padding-bottom: 100px;
  width: 300px;
  display: flex;
  align-items: flex-end;
  margin: auto;
  box-sizing: border-box;
`;

export default function App() {
  const numberToPushRef = useRef(3);
  const [list, { push, pop }, listInReverse] = useStackState([1, 2, 3]);

  function addToStack() {
    numberToPushRef.current = numberToPushRef.current + 1;
    push(numberToPushRef.current);
  }

  return (
    <Root>
      <div>
        <StackDiv>
          {listInReverse.map((item) => {
            return <StackItem key={item}>{item}</StackItem>;
          })}
        </StackDiv>
        <ActionButtons>
          <ActionButton onClick={addToStack}>Push</ActionButton>{" "}
          <ActionButton2 onClick={pop} warning>
            Pop
          </ActionButton2>{" "}
        </ActionButtons>
      </div>
    </Root>
  );
}

Inspect the top item and render newest-first

import { useStackState } from "rooks";

export default function UploadQueue() {
  const [queue, controls, newestFirst] = useStackState([
    "draft.pdf",
    "brief.png",
  ]);

  return (
    <div>
      <p>Next upload: {controls.peek() ?? "Nothing queued"}</p>
      <p>Items queued: {controls.length}</p>

      <button onClick={() => controls.push(`file-${controls.length + 1}.txt`)}>
        Add file
      </button>
      <button onClick={controls.pop} disabled={controls.isEmpty()}>
        Remove latest
      </button>
      <button onClick={controls.clear} disabled={controls.isEmpty()}>
        Clear queue
      </button>

      <ul>
        {newestFirst.map((item) => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

Arguments

ArgumentsTypeDescriptionDefault value
initialListany[]An arrayundefind

Returned array items

Returned itemsTypeDescription
pushfunctionPut an item to the top of the stack
popfunctionRemove the item on the top of the stack
peekfunctionReturn the item on the top of the stack
lengthnumberNumber of items in the stack

On this page