Giter Club home page Giter Club logo

react-hooks-helper's Introduction

react-hooks-helper

All Contributors

A custom React Hooks library that gives you custom hooks for your code.

npm version

react-hooks-helper

πŸ§™β€ useStep is a multi-purpose step wizard. Build an image carousel!

πŸ“‹ useForm for dead simple form control with nested object support.

🚦 useTrafficLight easily build a fun traffic light component.

β€Ό useNot to simplify toggling true / false without lambda functions.

🐐 Full 100% test coverage!

πŸ”₯ Blazing fast!

Requirement ⚠️

To use react-hooks-helper, you must use [email protected].

Installation

$ npm i react-hooks-helper

Usage

const { isPaused, index, step, navigation } = useStep(config);
const [{ foo, bar }, setForm] = useForm({ foo, bar });
const currentValue = useTrafficLight(initialIndex, durations);
const [bar, notBar] = useNot(bool);

Examples

useStep

The new useStep Hook is the new useTrafficLight and is a more general step wizard. You can use it to simplify many tasks, such as a multi-page input form, or an image carousel.

It has an auto advance function, or control manually by calling previous and/or next.

Usage

const { isPaused, index, step, navigation } = useStep(config);

Config

You pass useStep a configuration object containing the following (* = required).

Key Description
steps* Either an array containing the steps to process or an integer specifying the number of steps.
initialStep The starting stepβ€”either a string id or an index. Default = 0.
autoAdvanceDuration If you wish the steps to auto-advance, specify the number of milliseconds. You can also include an autoAdvanceDuration in each step in your steps array, if you wish to have different durations for each step.

Return object

Key Description
index A number containing the current step index.
step The current step object from the steps array.
navigation A navigation object (see below).
isPaused true if the autoAdvanceDuration is paused.
autoAdvanceDuration Duration of the current auto-advance.

Navigation object

The navigation object returned from useStep contains control callback functions as follows.

Key Description
previous Call to navigate to the previous item index. Wraps from the first item to the last item.
next Call to navigate to the next item index. Wraps from the last item to the first item.
go Call to navigate to a specific step by id or by index. Example: go(2) or go('billing-address')
pause Pause auto-advance navigation.
play Play auto-advance navigation once it has been paused.

Example

There's a simple multi-step control with 3 "pages". You use the "Previous" and "Next" buttons to navigate.

function App() {
  const {
    index,
    navigation: { previous, next },
  } = useStep({ steps: 3 });
  return (
    <div>
      <h1>Hello CodeSandbox</h1>

      {index === 0 && <div>This is step 1</div>}
      {index === 1 && <div>This is step 2</div>}
      {index === 2 && <div>This is step 3</div>}

      <div>
        <button disabled={index === 0} onClick={previous}>
          Previous
        </button>
        <button disabled={index === 2} onClick={next}>
          Next
        </button>
      </div>
    </div>
  );
}

Live demo

You can view/edit a photo carousel on CodeSandbox. It automatically advances after 5 seconds. You can also click previous/next, or navigate directly to a particular image.

image

Edit Carousel using hooks (rhh demo)

useForm

useForm is for an advanced search, sign-up form, etc, something with a lot of text felds, because you only need to use one hook. Wereas on the otherwise you would need many useState hooks.


Before

Right here is some code for a sign-up form. As you can see it is using two useState hooks and we need a lambda function to change it.

function App() {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [gender, setGender] = useState("Male");
  const [isAccept, setAcceptToC] = useState(false);
  return (
    <div className="App">
      <input
        type="text"
        value={firstName}
        onChange={(ev) => {
          setFirstName(ev.target.value);
        }}
      />
      <div>{firstName}</div>
      <input
        type="text"
        value={lastName}
        onChange={(ev) => {
          setLastName(ev.target.value);
        }}
      />
      <div>{lastName}</div>
      <div className="radio-group">
        <div className="radio">
          <input
            type="radio"
            value="Female"
            checked={gender === "Female"}
            onChange={(ev) => {
              setGender(ev.target.value);
            }}
          />{" "}
          Female
        </div>
        <div className="radio">
          <input
            type="radio"
            value="Male"
            checked={gender === "Male"}
            onChange={(ev) => {
              setGender(ev.target.value);
            }}
          />{" "}
          Male
        </div>
        <div>Selected Gender: {gender}</div>
      </div>
      <div>
        <div className="checkbox">
          <input
            type="checkbox"
            value="true"
            checked={isAccept === "true"}
            onChange={(ev) => {
              setAcceptToC(ev.target.checked);
            }}
          />{" "}
          I accept and agree Terms &amp; Conditions.
        </div>
      </div>
    </div>
  );
}

After

function App() {
  const [{ firstName, lastName, gender, isAccept }, setValue] = useForm({
    firstName: "",
    lastName: "",
    gender: "Male",
    isAccept: false,
  });
  return (
    <div className="App">
      <input
        type="text"
        value={firstName}
        name="firstName"
        onChange={setValue}
      />
      <div>{firstName}</div>
      <input type="text" value={lastName} name="lastName" onChange={setValue} />
      <div>{lastName}</div>
      <div className="radio-group">
        <div className="radio">
          <input
            type="radio"
            value="Female"
            checked={gender === "Female"}
            onChange={setValue}
          />{" "}
          Female
        </div>
        <div className="radio">
          <input
            type="radio"
            value="Male"
            checked={gender === "Male"}
            onChange={setValue}
          />{" "}
          Male
        </div>
        <div>Selected Gender: {gender}</div>
      </div>
      <div>
        <div className="checkbox">
          <input
            type="checkbox"
            value="true"
            checked={isAccept === "true"}
            onChange={setValue}
          />{" "}
          I accept and agree Terms &amp; Conditions.
        </div>
      </div>
    </div>
  );
}

You see useForm takes the name of your input and changes the object, so you only have to create one useForm. You can have as many items in the object, and this allows many inputs, but with still one useForm. And it eliminates the use of a lambda function.

Nest objects

useForm also supports nested objects. This is useful for things like billing.city and shipping.city.

In your markup, you simply add the dots in the name field like this.

<input
  type="text"
  value="{billing.city}"
  name="billing.city"
  onChange="{setValue}"
/>

Live demo

Edit useForm (rhh demo)

useTrafficLight


Before

const lightDurations = [5000, 4000, 1000];

const BeforeTrafficLight = ({ initialColor }) => {
  const [colorIndex, setColorIndex] = useState(initialColor);

  useEffect(() => {
    const timer = setTimeout(() => {
      setColorIndex((colorIndex + 1) % 3);
    }, lightDurations[colorIndex]);
    return () => clearTimeout(timer);
  }, [colorIndex]);

  return (
    <div className="traffic-light">
      <Light color="#f00" active={colorIndex === 0} />
      <Light color="#ff0" active={colorIndex === 2} />
      <Light color="#0c0" active={colorIndex === 1} />
    </div>
  );
};

After

const AfterTrafficLight = ({ initialColor }) => {
  const colorIndex = useTrafficLight(initialColor, [5000, 4000, 1000]);

  return (
    <div className="traffic-light">
      <Light color="#f00" active={colorIndex === 0} />
      <Light color="#ff0" active={colorIndex === 2} />
      <Light color="#0c0" active={colorIndex === 1} />
    </div>
  );
};

Live demo

Edit Traffic light using hooks (rhh demo)

useNot

useNot is a toggle function for React components.


Here is a simple App that toggles a value to produce either a blue or a red square.

Before

function App() {
  const [value, setValue] = useState(false);
  return (
    <div
      onClick={ value => (
        setValue( !value )
      )}
      style={{
        width: 100,
        height: 100,
        backgroundColor: value ? 'red' : 'blue'
      }}
    />
  );

After

function App() {
  const [value, notValue] = useNot(false);
  return (
    <div
      onClick={notValue}
      style={{
        width: 100,
        height: 100,
        backgroundColor: value ? "red" : "blue",
      }}
    />
  );
}

value, a boolean, is a variable. notValuefunction that nots the value from true to false and vise versa. Notice the notValue is not a lambda function, like in the before

Live demo

Edit useNot  (rhh demo)

My Coding Journey

On Dec 18, 2017, I did a talk at ReactNYC about the useTrafficLight code above, but it was the "before" code and did not use a custom hook, and certainly not react-hooks-helper because it was not out yet!

Here's my video.

YouTube

License

MIT Licensed

Code in the wild

Have you built an app (real or sample) using react-hooks-helper? Make a PR and add it to the list below.

Contributors

Thanks goes to these wonderful people (emoji key):

Revel Carlberg West
Revel Carlberg West

πŸš‡ ⚠️ πŸ’‘ πŸ€” 🚧 πŸ‘€ πŸ”§ πŸ’»
Donavon West
Donavon West

πŸ’» πŸ€” ⚠️
Sunil Pai
Sunil Pai

πŸ“–
Permadi Wibisono
Permadi Wibisono

πŸ’»
Jang Rush
Jang Rush

πŸ“–

This project follows the all-contributors specification. Contributions of any kind welcome!

react-hooks-helper's People

Contributors

allcontributors[bot] avatar dependabot[bot] avatar donavon avatar permadiwibisono avatar revelcw avatar threepointone avatar weakish avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-hooks-helper's Issues

Using multiple useStep's

I'm trying to use two useStep hooks in one function.
I tried this:

const steps = [
  { id: "name", Component: NameField },
  { id: "email", Component: EmailField },
  { id: "phoneNumber", Component: PhoneNumberField },
  { id: "message", Component: MessageField },
  { id: "review", Component: ReviewForm },
  { id: "confirmation", Component: ConfirmationForm },
];
const steps2 = [
  { id: "website", Component: WebsiteField },
  { id: "services", Component: ServicesField },
  { id: "overview", Component: OverviewField },
  { id: "budget", Component: BudgetField },
  { id: "reviewComplete", Component: ReviewCompleteForm },
];
const MultiStepForm = () => {

  const [formData, setForm] = useForm(defaultData);
  const { step, navigation, index } = useStep({ initialStep: 0, steps });
  const { step: quoteStep, navigation: quoteNavigation, index: quoteIndex } = useStep({ initialStep: 0, steps: steps2 });

}

but i get this Error:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Can we use multiple useStep hooks in the same function?

Using setForm manually on components without name/value

Maybe I am just to dump to figure it out, but is there a way to manually call the setForm function?

I am having a few special components that don't have a name or value, there fore I need to set the value manually.

What I am trying to do is something like this:

onChange={(checked) => { setForm(male, true) }} />

Really enjoying your project ! Keep it up!

Array objects Support

Does react-hooks-helper support the following structure?

{
    "foo": [
        {
            "a": "",
            "b": "",
            "c": ""
        }, 
        {
            "a": "",
            "b": "",
            "c": ""
        }
    ]
}

Checkbox input not saving checked state

I'm trying to implement a form with checkboxes like this:

{Object.entries(Services).map(([value, name]) => (
        <FormItem
          id={value}
          key={value}
          label={name}
          name={name}
          value={value}
         
          onChange={setForm}
          type='checkbox'
        />
      ))}

but when i click next and then back again (of course using navigation from your useStep helper) the checkbox i previously checked is not checked anymore. How can i fix this or i have to write separate function to keep the state?

Note: The state is saved just fine on other input types using useForm, except checkbox.

EDIT: The state is not saved on any field except type text. Noticed that even if the field is of type textarea, it's not saved

Form validation

Hello! πŸ‘‹

Thanks a lot for this library, it's quite simple and powerful!
I was wondering about the useForm hook. It's pretty good but I haven't seen anything about form validation. Are there any plans to include maybe another hook for that that would synergise with useForm?

ERESOLVE unable to resolve dependency tree

Im getting this error when trying to install using React 17.0.2:

`
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! react@"17.0.2" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0" from [email protected]
npm ERR! node_modules/react-hooks-helper
npm ERR! react-hooks-helper@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/ilirbajrami/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR! /Users/ilirbajrami/.npm/_logs/2022-05-11T15_38_10_815Z-debug-0.log
`

Support for "file" type

reacts-hooks-helper is a nice compact library that helps with forms and steps management.

When using the useForm() with input of type="file" , I found that the default binding does not preserve the values.
Any insights on how to use the helper with file inputs.

For example

const GetFileData = (props) => {
  const { formData, setForm } = useForm( initialData);
 
 // ... some code skipped


  return (
     <form>
            <input type="file" id="inputfile" name="inputfile" onChange={setForm} />
     </form>
  ); 

};

For example when I upload a file, say "TestFile.txt"

the resulting formData does not have the file, but instead only has the file name as:
formData = { inputfile: "c:\fakepath\TestFile.txt" }

is there a workaround?

Delete an entry from formData

Hello!
thank you very much for this library, it's really useful when managing big forms.
Is there a way to remove an entry from formData? I want to make a list of input boxes with a delete button beside every input box. Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.