react-grapple
v1.6.0
Published
A collection of useful hooks that I made.
Downloads
31
Readme
🙋♂️ Made by @koenbrouwer.
Welcome to react-grapple 👋
A collection of useful hooks that I made. This is a Node.js package available through the npm registry.
You can install react-grapple
with the npm install
command.
Install
npm install --save react-grapple
Usage
useToggle
const [state, toggleState] = useToggle(); // defaults to false
You can also give it another default initial state:
const [state, toggleState] = useToggle(true); // defaults to true
If you don't give it a default value, it will default to false
, or the boolean you feed it.
Then, toggleState()
will toggle the value from true
to false
, or false
to true
.
useConditionalByTime
I was recently at a conference where the website would still sell tickets after the event had already ended.
That's of course bad practice. It would be much better to show some video recordings from the event or maybe
a list of upcoming events. So to automate this, you can use the useConditionalByTime
hook.
(If you know a better name for this hook, let me know @KoenBrouwer)
const [Before, After] = useConditionalByTime(date, realtime); // date is of type Date, realtime is a boolean
You can pass a Date
object as the first argument. The hook then returns two new components in an array,
which you can use to wrap your components to be displayed before the splitDate and after. Because of array
destructuring, you can use your own names for those components, but for the sake of simplicity, we just used Before
and After
here.
You can pass true
as the second argument if you want the hook to actively keep track of time and rerender realtime.
Here's an example for your awesome event landing page:
import React from "react";
const App: React.FC = () => {
const eventStartDate = new Date("2020-04-30 14:00");
const [Before, After] = useConditionalByTime(eventStartDate, true);
return (
<div className="App">
<h1>React Live, Amsterdam 2020</h1>
<Before>
<p>
Buy your tickets to this event now!
</p>
<BuyTickets />
</Before>
<After>
<p>
Wow, that was an awesome conference! Take a look at our schedule for next year!
</p>
<Schedule />
</After>
</div>
);
}
So, everything inside <Before>
will be rendered if the date is in the future, and everything inside <After>
is rendered if the date is in the past.
Because we've passed true
as the second argument of the useConditionalByTime
hook, the page gets rerendered automatically once the date passes.
useInput
Handling change events on input fields is always a tedious process. Not with the useInput
hook and easy binding.
There are two ways of initializing the useInput hook. First way is to give it one argument of type string
, which represents the default value of the input field. The input field that gets rendered will be prepopulated with this defaultValue.
const field = useInput(initialValue); // initial value is always a string.
You can also pass an object of options as an argument to useInput()
that implements the UseInputOptions
interface. This way, you can add validations rules to your field. Here's an example:
const field = useInput({
defaultValue: "",
validate: [Validators.required, Validators.password, Validators.mail]
});
There's currently some built-in validators, available from the Validators
object:
Validators.required
- the field cannot be left empty or filled with spaces.Validators.email
- tests the field value agains a Regex pattern for email addresses.Validators.password
- requires the field value to:- Contain at least 8 characters
- Contain at least one uppercase letter (A-Z)
- Contain at least one lowercase letter (a-z)
- Contain at least one number (0-9)
- Contain at least one number that is none of the above (special characters)
You can also add your own validator function that returns true or false:
const field = useInput({
validate: [Validators.required, (value: string) => value === "whatever"]
});
ℹ️ For now, useInput only supports text inputs. I might add checkboxes, radios and selects in a future version, once I feel like I need them. If you wish to add them to the library yourself, feel free to open a pull request if you have a solution.
Anyway, just define the fields for your form like this:
const name = useInput("");
const city = useInput("");
const country = useInput("Netherlands");
Then bind the value and change handler to your input element like this:
<input type="text" {...name.bind} /> -> <input type="text" value={name.value} onChange={name.onChange} ref={name.ref} />
<input type="text" {...city.bind} /> -> <input type="text" value={city.value} onChange={city.onChange} ref={city.ref} />
<input type="text" {...country.bind} /> -> <input type="text" value={country.value} onChange={country.onChange} ref={country.ref} />
On an <input>
, bind
will just pass a value
and onChange
to the input, and will handle changes for you. The useInput
hook will also create a reference to every input field that is accessible via the ref
property.
After binding, you can reference the value
and ref
of the input like this:
name.value // returns the value for this field
name.ref // holds the RefObject for this field
This ref comes in handy when you wish to talk to the input field directly, for example focus on the input:
const name = useInput("");
name.ref.focus();
Some other useful properties and methods you can call on the result of useInput()
:
isValid
will be true if all validation rules return true. Updates automatically usingonChange
.
Since v1.5.0
clear
has been renamed toreset
.
reset()
sets the value of the field to""
.setValue()
sets the value of the field to whatever you pass to it, if you ever need to set the value manually.dirty
indicates with a boolean if the field has changed since initial render.
useNumberInput
This is basically an extension to useInput
, but bind
contains a couple more fields: min
, max
, step
and type="number"
.
const nOrders = useNumberInput(1); // default value 1
You can also configure them in the options
instead of passing a default value:
const nOrders = useNumberInput({
defaultValue: 1,
max: 10,
min: 2,
step: 0.1
});
Then bind to an input as usual:
<input {...nOrders.bind} />
useIsMobile
This hook uses window.innerWidth to detect if the current viewport is "mobile" or not.
It has a default breakpoint of 650px. You can also pass a custom breakpoint as the only argument.
When the window resizes, isMobile
updates.
const isMobile = useIsMobile(); // return true if window.innerWidth < 650
const isMobile = useIsMobile(450); // return true if window.innerWidth < 450
useIsMobileOnce
Same as useIsMobile
, execpt that isMobile
it doesn't update when the window resizes.
Author
👤 Koen Brouwer
- Website: KoenBrouwer.com
- Twitter: @KoenBrouwer
- Github: @KoenBrouwer
🤝 Contributing
Feel free open an issue on the issues page or a pull request in the repo on GitHub!
Show your support
Give a ⭐️ if this project helped you!
License
Contributions, issues and feature requests are welcome!