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 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-sync-ui

v1.0.3

Published

`react-sync-ui` promisify your React Components and make your UI awaitable.

Downloads

1,061

Readme

react-sync-ui

react-sync-ui promisify your React Components and make your UI awaitable.

usage example

<button
  onClick={async () => {
    // call synchronous UI workflow with promisified React components

    const likeSyncUI = await syncConfirm("Do you like this library?");

    if (likeSyncUI) {
      await syncAlert("Thanks, we like you too");
    } else {
      const isUserSure = await syncConfirm("Are you sure?");
      if (isUserSure) {
        await syncAlert("Try to give it a second try");
      } else {
        await syncAlert("Thanks, we like you too");
      }
    }
  }}
>
  Run
</button>

Sync UI preview

<button
  onClick={async () => {
    const name = await syncPrompt("Fill your name");

    while ((await syncPrompt(`Fill your password!`)) !== "1234") {
      await syncAlert("Invalid password, keep trying");
    }

    await syncAlert(`Congratulation ${name}, you are logged in`);
  }}
>
  Login
</button>

Sync UI preview

react-sync-ui provides function makeSyncUI<InputData, ResolveValue> which transform your declarative React Components into the promisified awaitable functions.

// defining of your custom react-sync-ui component
export const syncAlert = makeSyncUI<string, void>((props) => (
  <Modal isOpen toggle={() => props.resolve()}>
    <ModalHeader>{props.data}</ModalHeader>
    <ModalFooter>
      <Button onClick={() => props.resolve()}>OK</Button>
    </ModalFooter>
  </Modal>
));

what is react-sync-ui solving?

For a long time, I did not like that React's functional way of declarative UI forced you to write nice UI code, but with ugly distributed business logic. When you have a complex business use case which is a composition of asynchronous actions like HTTP requests together with user interactions, your business logic code is distributed over many async React handlers and it's really hard to understand the sequence of business logic.

People very often solve this problem by dependencies in the useEffect(..., [dependency]) which transfer React logic to the event-driven architecture. When you change the dependency variable value, the different components will register the dependency change, and useEffect will be re-called. With this event-driven programming style, your code complexity is 1000 times more complex, and your newcomer programmes who see the code have the business workflow is.

A nice solution for this problem is to wrap your declarative React components into Promise wrappers which split your UIs into many smaller functions that can be simply composed together inside of your Javascript function and you'll get very complex business logic in just a few lines of code.

Thanks to react-sync-ui you can simply promisify your React Components UI and make your UI awaitable.

And that's why react-sync-ui was created. ❤

PS: I took inspiration from awesome functions: window.alert, window.confirm and window.prompt.

Installation

npm i react-sync-ui

Usage

Setup <SyncUI /> Component into the root of yout project

import { SyncUI } from 'react-sync-ui'

const App = () => (
  <>
    <SyncUI />
    <YourAppStuffs />
  <>
)

const root = createRoot(document.getElementById('root')!);
root.render(<App />);

create sync UI

Now, you just have to define your custom React component which will be promisifed by makeSyncUI function.

makeSyncUI returns Promise which render your custom React Component. Promise will be resolve when you call props.resolve(any) inside of your custom UI.

Alert example

import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from "reactstrap";
import { makeSyncUI } from "react-sync-ui";

export const syncAlert = makeSyncUI<string, void>((props) => (
  <Modal isOpen={true} toggle={() => props.resolve()}>
    <ModalHeader>{props.data}</ModalHeader>
    <ModalFooter>
      <Button onClick={() => props.resolve()}>OK</Button>
    </ModalFooter>
  </Modal>
);


// usage:

<button
  onClick={async () => {
    await syncAlert("Wait for it...");
    await syncAlert("Wait for it...");
    await syncAlert("You're hacked");
  }}
>
  click to me
</button>;

Prompt example

import { Button, Modal, ModalBody, ModalFooter } from "reactstrap";
import { makeSyncUI } from "react-sync-ui";

export const syncPrompt = makeSyncUI<string, string>((props) => {
  const [input, setInput] = React.useState("");

  return (
    <Modal
      toggle={() => props.reject(new Error("User forced close prompt modal"))}
      isOpen={true}
    >
      <form
        onSubmit={(e) => {
          e.preventDefault();
          setInput("");
          props.resolve(input);
        }}
      >
        <ModalBody>
          <label>
            {props.data}
            <input
              value={input}
              onChange={(e) => setInput(e.target.value)}
              type="text"
            />
          </label>
        </ModalBody>

        <ModalFooter>
          <Button type="submit">Accept</Button>
        </ModalFooter>
      </form>
    </Modal>
  );
});

// usage:

<button
  onClick={async () => {
    const usersFeelings = await syncPrompt("how are you");
  }}
>
  click to me
</button>;

Confirm example

import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from "reactstrap";
import { makeSyncUI } from "react-sync-ui";

export const syncConfirm = makeSyncUI<
  {
    title: string;
    description?: string;
    okBtn?: string;
    notOkBtn?: string;
  },
  boolean
>((props) => (
  <Modal isOpen={true} toggle={() => props.resolve(false)}>
    <ModalHeader>{props.data.title}</ModalHeader>

    <ModalBody>{props.data.description}</ModalBody>

    <ModalFooter>
      <Button autoFocus onClick={() => props.resolve(true)}>
        {props.data.okBtn ?? "Yes"}
      </Button>
      <Button onClick={() => props.resolve(false)}>
        {props.data.notOkBtn ?? "No"}
      </Button>
    </ModalFooter>
  </Modal>
));

// usage:

<button
  onClick={async () => {
    const isOk = await syncConfirm({
      title: "How are you",
      okBtn: "Good",
      notOkBtn: "Not good",
    });
  }}
>
  click to me
</button>;

Advance use-case, Multiple async queues

You're able to initialized multiple independent instances of react-sync-ui queue.

Multiple instances are made by xxx

import { syncUIFactory } from "react-sync-ui";

export const syncUI1 = syncUIFactory();
export const syncUI2 = syncUIFactory();

You may check the full multiple queue example here

react-sync-ui/example/MultiQueuesApp.tsx