npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

boo-state

v1.0.3

Published

Yet another react state management library

Downloads

10

Readme

Example

A super tiny state management library that only contains 2 functions.

Overview

class AuthService {
  get isLoggedIn() { return !isNil(this.token); }

  async login() {
    const resp = await fetch(/* ... */);
    
    // Below mutations automatically trigger components update
    this.user = resp.user;
    this.token = resp.token;
  }
}
const AuthComponent = () => {
  const auth = useService(AuthService);
  
  const onClickLogin = (id, pw) => {
    auth.login(id, pw);
  };
  
  return (
    { auth.isLoggedIn && <LoginComponent onClickLogin={onClickLogin} /> }
    { !auth.isLoggedIn && <UserProfileComponent /> }
  ); 
};

useComponentService

use useComponentService in case that you want to control more than one instances.

// Get or create per-component service instance.
const auth = useComponentService(AuthService);

getService

class PostService {
  async write() {
    const auth = getService(AuthService);
    /* ... */
  }
}

Error Handling

using catch

const onClickLogin = async (id, pw) => {
  try {
    await auth.login(id, pw);
  } catch(e) {
    /* do something */
  }
};

using useApi

const auth = useService(AuthService);
const login = useApi(auth.login);

const onClickLogin = (id, pw) => {
  login(id, pw);
};

return (
  { login.isFetching && "Please wait..." }
  { login.loginResult && "You are successfully logged in" }
  { login.error && "Login failed" }
);

변경 감지

useService는 자동으로 각 컴포넌트가 어떤 property를 구독하는지에 대한 Map을 생성합니다. 이는 특정 프로퍼티가 변경되었을 때, 모든 컴포넌트를 다시 렌더링하는 대신 해당 프로퍼티를 사용하는 컴포넌트만 업데이트 할 수 있도록 해줍니다.

class UserService {
  changeNickname(newNickname) {
    // 이 함수는 UserStatusComponent의 re-render를 실행하지 않습니다.
    this.nickname = newNickname;
  }
  setUserStatus(newStatus) {
    // 같은 원리로, 이 함수는 UserProfileComponent re-render를 실행하지 않습니다.
    this.status = newStatus;
  }
}
const UserProfileComponent = () => {
  const user = useService(UserService);
  return (
    <div>
      Nickname: {user.nickname}
    </div>
  );
};
const UserStatusComponent = () => {
  const user = useService(UserService);
  return (
    <div>
      Status: {user.status}
      
      <div>
        Set As
        <button onClick={() => user.setUserStatus('online')}> ONLINE </button>
        <button onClick={() => user.setUserStatus('away')}> AWAY </button>
      </div>
    </div>
  );
};

구독 시점

useService는 오직 렌더링 과정에서 발생한 읽기 작업만 구독으로 간주합니다. 아래 코드에서 isLoggedInnickname은 렌더링 이후에 발생할 작업들이기 때문에 해당 프로퍼티가 바뀌어도 컴포넌트가 다시 렌더링되지 않습니다.

const AuthComponent = () => {
  const user = useService(UserService);
  
  const onClickLogin = (id, pw) => {
    if (user.isLoggedIn) return;
    login(id, pw);
  };
  
  useEffect(() => {
    console.log(user.nickname);
  }, []);
  
  return (
    <div>
      /* ... */
    </div>
  );
};

구독 갱신

컴포넌트의 로컬 state에 따라서 구독하는 프로퍼티가 달라지는 경우가 있습니다. 이전에 구독했던 프로퍼티가 더 이상 필요하지 않을 수도 있고, 새로운 프로퍼티를 구독해야할 경우도 있습니다. useService는 가장 마지막 렌더링 작업에서 요청된 프로퍼티들만을 기억하기 때문에 이러한 작업은 자동으로 처리됩니다.

const Foo = () => {
  const user = useService(UserService);
  const [mode, setMode] = useState(0);
  
  if (mode === 0) return (<div>{user.nickname}</div>);
  else if (mode === 1) return (<div>{user.status}</div>);
  else return (<div>{user.createdAt}</div>);
};

Peek

만약 프로퍼티를 구독하고자 하는게 아니라, 단순히 읽고 싶으면 __peek 메소드를 사용합니다.

const user = useService(UserService);
const status = user.__peek('status');

주의 __peek은 1회성 동작이며, 컴포넌트 내에 다른 읽기 동작이 있을 경우 최종적으로는 해당 컴포넌트는 status를 구독하게 됩니다.

const user = useService(UserService);
const status = user.__peek('status');

return (
  <div>{user.status}</div>
)