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

use-destructuring

v0.1.4

Published

useDestructuring() is a function that destructures React setState functions

Downloads

2

Readme

useDestructuring

When calling useDestructuring matching setState function for each property in an object are created. The primary use case of useDestructuring is for simplifying forms in React.

import { useState } from "react";
import useDestructuring from "use-destructuring";

interface Person {
    firstName: string;
    lastName: string;
}

export const PersonForm: React.FC = () => {
    
    const [person, setPerson] = useState<Person>({ firstName: 'John', lastName: 'Smith' });

    const { firstName, lastName } = person; // Javascript object destructuring
    const { setFirstName, setLastName } = useDestructuring(person, setPerson);

    return (
        <form>
            <input type="text" value={firstName} onChange={e => setFirstName(e.target.value)} />
            <input type="text" value={lastName} onChange={e => setLastName(e.target.value)} />
        </form>
    );
};

Getting Started

First install use-destructuring using NPM

npm install use-destructuring

or if you are using Yarn

yarn add use-destructuring

then import it inside your React project

import useDestructuring from "use-destructuring";

Using Destructuring for Abstraction

Although the first example can easily be implemented without using useDestructuring, once your forms grow in complexity useDestructuring allows you to easily abstract form components in multiple ways.

import { useState } from "react";
import useDestructuring from "use-destructuring";

interface Person {
    firstName: string;
    lastName: string;
}

type Props = {
    person: Person;
    setPerson: React.Dispatch<React.SetStateAction<Person>>;
}

export const PersonForm: React.FC<Props> = ({ person, setPerson }) => {

    const { firstName, lastName } = person; // Javascript object destructuring
    const { setFirstName, setLastName } = useDestructuring(person, setPerson);

    return (
        <Form>
            <TextInput text={firstName} setText={setFirstName} />
            <TextInput text={lastName} setText={setLastName} />
        </Form>
    );
};

type TextInputProps = {
    text: string,
    setText: React.Dispatch<React.SetStateAction<string>>
}
const TextInput: React.FC<TextInputProps> = ({ text, setText }) => {
    return (<input type="text" value={text} onChange={e => setText(e.target.value)} />);
};

The PersonForm itself can easily become a reusable component that lets you freely move the Person state among its parent components. At the same time, it allows the implementation of form fields that need not know about the structure of the Person object.

Arrays

useDestructuring also supports destructuring of arrays. For example, our Person object from before might contain a list of telephone numbers. Simply extend the PersonForm like you would any other property. In this example the list of phone numbers is handled in a separate component.

PersonForm.tsx

interface Person {
    firstName: string;
    lastName: string;
    phoneNumbers: string[];
}

export const PersonForm: React.FC<Props> = ({ person, setPerson }) => {

    const { firstName, lastName, phoneNumbers } = person;
    const { setFirstName, setLastName, setPhoneNumbers } = useDestructuring(person, setPerson);

    return (
        <Form>
            <TextInput text={firstName} setText={setFirstName} />
            <TextInput text={lastName} setText={setLastName} />
            <PhoneNumbersInput phoneNumbers={phoneNumbers} setPhoneNumbers={setPhoneNumbers} />
        </Form>
    );
};

In the PhoneNumbersInput component call useDestructuring to get a list of tuples destructuredPhoneNumbers in which each tuple contains one entry of [phoneNumber, setPhoneNumber, removePhoneNumber]. The first value is just the value in the phoneNumbers[i] array itself, the second is a SetState function that overwrites that array element at index i and the third removes the element at position i from the array.

PhoneNumbersInput.tsx

type Props = {
    phoneNumbers: string[];
    setPhoneNumbers: React.Dispatch<React.SetState<string[]>>;
}

export const PhoneNumbersInput: React.FC<Props> = ({ phoneNumbers, setPhoneNumbers }) => {

    const destructuredPhoneNumbers = useDestructuring(phoneNumbers, setPhoneNumbers);

    return (
        <fieldset>
            { destructuredPhoneNumbers.map(([phoneNumber, setPhoneNumber, removePhoneNumber]) => (
                <span key={phoneNumber}>
                    <TextInput text={phoneNumber} setPhoneNumber={setPhoneNumber} >
                    <button type="button" onClick={() => removePhoneNumber()}>X</button>
                </span>
            )) }
            <button type="button" onClick={
                () => setPhoneNumbers(oldPhoneNumbers => [...oldPhoneNumbers, '+01234567'])
            }>Add New Telephone Number</button>
        </fieldset>
    );
}

To add additional phone numbers to the list of existing phone numbers, you can just use the setPhoneNumbers function which is already present.

Performance

Per default React will rerender the entire form and ALL its child components if some property of the form component state is changed. To only rerender components which have their props changed React components can be wrapped in React.memo calls. To support the usage of React.memo, useDestructuring saves all its produced setter functions so that they do not change from one rerender to the next, much like useState (but not exactly). That means that in the ideal scenario only the leaf component that is edited and all its parents up until the component that holds the form state are rerendered. Rerender counts can be reduced further by implementing a debounce in leaf fields that do not immidiately call setState (e.g. wait while the user is typing).