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

react-compose-io

v1.1.2

Published

Better way to create your React Components

Downloads

27

Readme

ComposeIO

A compose-io é uma biblioteca que propõe uma forma diferente de se criar componentes em React.

Instalação

  • Certifique-se de que o React esteja instalado no seu projeto!
  • Para instalar esta biblioteca você deve executar o seguinte comando:
yarn add react-compose-io

Princípios

O principal objetivo desse pacote é deixar explícitas e separadas as partes visuais e lógicas de um componente. Sendo assim, um componente é composto por uma View e por sua lógica que, por convenção, é chamada de IO. Com isso, fica mais fácil de entender como que uma tela funciona e o que o componente realmente faz durante a sua execução. Adotando uma estratégia mais declarativa e orientada ao paradigma funcional, o componente passa representar o que uma feature ou funcionalidade faz e não como ele faz isso.

Ao criar um componente você precisa pensar nos seguintes princípios:

  • Uma view não possui nenhuma lógica que não seja de renderização
  • Uma view se assemelha a uma função pura, ou seja, ela só recebe argumentos e retorna um resultado.
  • Todos os estados, as chamadas de api, as funções que mudam o estado global e os handlers de eventos devem ficar no IO

Exemplo

A estrutura de arquivos de um componente possui os seguintes aquivos:

  • Componente.view.tsx
  • Componente.io.ts
  • index.ts

A construção de um componente de um botão seria da seguinte forma:

// button/Button.view.tsx
import React from "react";
import { IOProps } from "react-compose-io";
import { ButtonIO } from "./Button.io";

export type ButtonProps = {
  text: string;
  onClick: () => void;
};

function ButtonView({ text, _io }: IOProps<ButtonIO, ButtonProps>) {
  return (
    <div>
      <button onClick={_io.onClick}>{text}</button>
    </div>
  );
}

// button/Button.io.ts
import { useEffect, useState, MouseEvent } from "react";
import { ButtonProps } from "./Button.view";

export function buttonIO({ onClick }: ButtonProps) {
  const [color, setColor] = useState("blue");

  useEffect(() => {
    console.log("Color changed!");
  }, [color]);

  return {
    color,
    onClick: (e: MouseEvent) => {
      e.preventDefault();
      setColor("green");
      onClick();
    },
  };
}

export type ButtonIO = ReturnType<typeof buttonIO>;

// button/index.ts
import { composeIO } from "react-compose-io";
import { ButtonView } from "./Button.view";
import { buttonIO } from "./Button.io";

const Button = composeIO(ButtonView, buttonIO);

export default Button;

O composeIO introduz uma nova forma de lidar com as props de um componente. Na View, são definidas as props externas, ou seja, aquelas que o componente irá receber quando for utilizado em outras partes da aplicação. No arquivo Button.view.tsx essas props são as ButtonProps. Além das props externas, a View recebe uma prop especial chamada _io.

Esta prop é chamada de prop interna por ser o objeto retornado pelo IO que não é visível para os outros componentes. Sendo assim, tudo que é retornado pela função buttonIO que está definida no arquivo Button.io.ts estará disponível na view através da prop _io.

Na definição da View, é utilizado um utilitário para facilitar a tipagem do componente: o IOProps.

function ButtonView({ text, _io }: IOProps<ButtonIO, ButtonProps>) { ... }

O IOProps recebe como argumentos o tipo de retorno do IO, que no caso está sendo exportado como ButtonIO no arquivo Button.io.ts, as props da View que no caso são as ButtonProps. Esse utilitário irá realizar a tipagem correta da prop interna _io em conjunto com as props da View.

Na definição do IO, pode-se notar que são recebidos como argumento as props externas.

export function buttonIO({ onClick }: ButtonProps) { ... }

Sendo assim, é possível manipular tanto as props externas quanto internas dentro do IO. É recomendado que o IO gerencie qualquer efeito colateral ou manipulação de dados e a que a View fique focada somente em chamar as funções e utilizar os valores das props.

O que não fazer

O composeIO defende fortemente a separação de atribuições e responsabilidades para que o código fique declarativo e de fácil entendimento.

Não utilize hooks dentro de uma View

Dê preferência para o IO quando for utilizar qualquer hook e repasse para a View apenas os valores necessários.

// Errado

function View({ count }: IOProps<Props, IO>) {
  const dispatch = useDispatch();

  // Não utilize esse useEffect aqui
  useEffect(() => {
    dispatch(algumaAction());
  }, [count]);

  return (
    <div>
      <span>{count}</span>
    </div>
  );
}
// Correto

// ???.view.tsx
function View({ count }: IOProps<Props, IO>) {
  return (
    <div>
      <span>{count}</span>
    </div>
  );
}

// ???.io.ts
function IO({ count }: Props) {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(algumaAction());
  }, [count]);

  return {};
}

Delegue a lógica de chamada das funções para o IO

// Errado

// ???.view.tsx
function View({ onChange, onClick, _io }: IOProps<Props, IO>) {
  return (
    <div>
      <input
        name="input-incorreto"
        onChange={(e) => {
          onChange(e);
          _io.onChange(e);
        }}
      />
      <button
        onClick={() => {
          onClick();
          _io.onClick();
        }}
      >
        Clique-me
      </button>
    </div>
  );
}
// Correto

// ???.view.tsx
function View({ onChange, onClick, _io }: IOProps<Props, IO>) {
  return (
    <div>
      <input name="input-incorreto" onChange={_io.onChange} />
      <button onClick={_io.onClick}>Clique-me</button>
    </div>
  );
}

// ???.io.ts
function IO({ onClick, onChange }: Props) {
  return {
    onClick: () => {
      onClick();
      // Aqui agora você pode fazer a lógica que quiser
    },
    onChange: () => {
      onChange();
      // Aqui agora você pode fazer a lógica que quiser
    },
  };
}