Tutorial
Rapid Prototyping Made Easy with React PowerPlug
While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.
If you’re trying to rapid prototype an app the last thing you want to be doing is implementing the same state management logic over and over. Adding something like Redux can help but tends to just adds a layer of complexity that can slow you down every further. React PowerPlug makes rapid prototyping a breeze by introducing a set of stateful components that let you focus on the good stuff, actually prototyping!
React PowerPlug is a set of renderless components that provide different types of state management scenarios by way of render props. The project is dependency-free, well documented and pretty small at around 3kb.
A word of warning though, the project’s master
branch is still considered unstable and under active development. I opted to talk about the unstable version because it has so much more to offer in terms of different types of stateful components.
Getting Started
To get things started, we will need to add React PowerPlug to our project:
Via npm
$ npm install --save react-powerplug
Or via Yarn
$ yarn add react-powerplug
With the dependency added to our project, we will need to import React PowerPlug in it’s entirety:
import ReactPowerPlug from "react-powerplug";
Or import the individual components we’d like to use:
import { Counter, Hover, Togggle } from "react-powerplug";
Examples
As mentioned, the master
branch of this project has a ton of additional stateful components.
While the type of data may be different between the components, nearly all of the components accept an initial
property to set the default state.
Managing State
A component’s state can come in many different forms. It could be as simple as holding a single value or as complex as a mixed bag of boolean values, counters and string values.
State
State
is one of the more basic components. Very similar to React’s baked in state
property, State
allows you to maintain an object of state properties that can updated via setState
:
<State initial={{ favorite: "", picked: "" }}>
{({ state, setState }) => (
<div>
<button
onClick={() =>
setState({
favorite: "Alligator",
picked: new Date().toLocaleTimeString()
})
}
>
Alligator
</button>
<button
onClick={() =>
setState({
favorite: "Crocodile",
picked: new Date().toLocaleTimeString()
})
}
>
Crocodile
</button>
<button onClick={() => setState({ favorite: "", picked: "" })}>
Reset
</button>
{state.favorite && state.picked && (
<div>
<br />You picked {state.favorite} at {state.picked}
</div>
)}
</div>
)}
</State>
Toggle
Toggle
is a component for maintaining the state of a boolean value:
<Toggle initial={false}>
{({ on, toggle }) => (
<div>
<input type="checkbox" checked={on} onChange={toggle} />
<br /><br />
{on && <div>This box is CHECKED!</div>}
{!on && <div>This box is NOT CHECKED!</div>}
</div>
)}
</Toggle>
Counter
Counter
allows you to increment and decrement an integer in the state:
<Counter initial={0}>
{({ count, inc, dec }) => (
<div>
{count === 0 && <div>There are no little alligators</div>}
{count === 1 && <div>There is 1 little lonely alligator</div>}
{count > 1 && <div>There are {count} little alligators</div>}
<div>
<br />
<button onClick={dec}>-</button>
<button onClick={inc}>+</button>
</div>
</div>
)}
</Counter>
Value
Value
is for maintaining the state of a single value. Set it and forget it:
<Value initial="#008F68">
{({ value, set }) => (
<div>
<div
style={{
height: 100,
width: 100,
background: value,
margin: "0 auto"
}}
/>
<div>
<br />
<button onClick={() => set("#008F68")}>#008F68</button>
<button onClick={() => set("#6DB65B")}>#6DB65B</button>
<button onClick={() => set("#4AAE9B")}>#4AAE9B</button>
</div>
</div>
)}
</Value>
Map
The Map
component is quite similar to State
as it controls state as an object with different properties. Where it differs is that you interact with the state via get
and set
methods:
<Map initial={{ reptile: "", picked: "" }}>
{({ set, get }) => (
<div>
<button
onClick={() => {
set("favorite", "Alligator");
set("picked", new Date().toLocaleTimeString());
}}
>
Alligator
</button>
<button
onClick={() => {
set("favorite", "Crocodile");
set("picked", new Date().toLocaleTimeString());
}}
>
Crocodile
</button>
<button
onClick={() => {
set("favorite", "");
set("picked", "");
}}
>
Reset
</button>
{get("favorite") &&
get("picked") && (
<div>
<br />You picked {get("favorite")} at {get("picked")}
</div>
)}
</div>
)}
</Map>
Set
Not to be confused with the aforementioned set
method, the Set
component manages it’s state as an array of values which you can add
to and remove
from:
<Set initial={["Alligator", "Crocodile"]}>
{({ values, add, remove }) => (
<div>
{values.length === 0 && <div>Our set is empty!</div>}
{values.length > 0 && (
<div>
{values.map(value => (
<div>
{value}
<button onClick={() => remove(value)}>X</button>
<br /><br />
</div>
))}
</div>
)}
<input
type="text"
placeholder="Type here and hit enter"
onKeyPress={event => {
if (event.key === "Enter") {
add(event.target.value);
event.target.value = "";
}
}}
/>
</div>
)}
</Set>
List
List
also holds it’s state as an array. Instead of simple add
and remove
methods, you interact with the array via push
and pull
methods.
Considering the complexity that is introduced by needing to know the index of the array item when pull
ing from the state, I’d probably just stick to Set
:
<List initial={["Alligator", "Crocodile"]}>
{({ list, push, pull }) => (
<div>
{list.length === 0 && <div>Our list is empty!</div>}
{list.length > 0 && (
<div>
{list.map(item => (
<div>
{item}
<button onClick={() => pull(i => item === i)}>X</button>
<br /><br />
</div>
))}
</div>
)}
<input
type="text"
placeholder="Type here and hit enter"
onKeyPress={event => {
if (event.key === "Enter") {
push(event.target.value);
event.target.value = "";
}
}}
/>
</div>
)}
</List>
Managing User Interactions
Keeping track of a user’s interaction with a component usually includes binding event handlers on top of keeping track of the current state. React PowerPlug does a great job of not only combining these implementations but also keeping you fairly insulated from needing to worry about event handlers.
Hover
Hover
keeps track of whether or not a user is hovering over a component:
<Hover>
{({ hovered, bind }) => (
<div {...bind}>
{!hovered && <div>See you later, alligator!</div>}
{hovered && <div>After 'while, crocodile!</div>}
</div>
)}
</Hover>
Active
Active
knows if a user is clicking on a component:
<Active>
{({ active, bind }) => (
<div {...bind}>
{!active && <span>Click here to activate!</span>}
{active && <span>STOP CLICKING ME!!</span>}
</div>
)}
</Active>
Touch
Similar to Active
, the Touch
component is the touch-friendly equivalent:
<Touch>
{({ touched, bind }) => (
<div {...bind}>
{!touched && <span>Touch here to trigger!</span>}
{touched && <span>STOP TOUCHING ME!!</span>}
</div>
)}
</Touch>
Focus
Focus
is perfect for showing and hiding information based on which field a user is currently interacting with:
<Focus>
{({ focused, bind }) => (
<div>
<input
type="text"
placeholder="Click to focus this input!"
{...bind}
/>
<div>
{focused
? "Great for showing help text ONLY when focused!"
: ""}
</div>
</div>
)}
</Focus>
Forms
Even though React PowerPlug has components that could easily be used to wrap up form components, they still took the time to include some form-specific components to help save you time:
Input
Input
, which works with input
instead of replacing it, binds input events to an input
or any form field and stashes the value in the state:
<Input initial="">
{({ bind, value }) => (
<div>
<input type="text" {...bind} />
<div>
{value.length
? `You typed: ${value}`
: "You have not typed anything :("}
</div>
</div>
)}
</Input>
Form
The Form
component takes things a step further by allowing you to track the state of multiple fields on a form with ease:
<Form initial={{ firstName: "", lastName: "" }}>
{({ input, values }) => (
<form
onSubmit={e => {
e.preventDefault();
console.log("Form Submission Data:", values);
}}
>
<input
type="text"
placeholder="Your First Name"
{...input("firstName").bind}
/>
<input
type="text"
placeholder="Your Last Name"
{...input("lastName").bind}
/>
<input type="submit" value="All Done!" />
</form>
)}
</Form>
Timers
React PowerPlug isn’t just for tracking state variables and user input, you can also use it wire up components to update automatically.
Interval
Unlike the other components we’ve discussed, Interval
doesn’t take an initial
state value and instead takes delay
(in milliseconds).
<Interval delay={1000}>
{({ start, stop, toggle }) => (
<div>
Updates every second, last updated at:{" "}
{new Date().toLocaleTimeString()}
<br /><br />
<div>
<button onClick={() => stop()}>Stop</button>
<button onClick={() => start()}>Start</button>
{" or "}
<button onClick={() => toggle()}>Toggle!</button>
</div>
</div>
)}
</Interval>
Conclusion
React PowerPlug stands up to the claims that it makes it easy to rapid prototype apps in React. As the project is very much a work in progress right now, I’m super excited to see where the team ends up taking it!
I hope that you enjoyed this run down of React PowerPlug and if you are interested in seeing the code samples in action, you can head over to CodeSandbox.