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.
To get things started, we will need to add React PowerPlug to our project:
$ npm install --save react-powerplug
$ 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";
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.
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
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
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
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
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>
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>
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
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>
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
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
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>
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
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>
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
, 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>
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>
React PowerPlug isn’t just for tracking state variables and user input, you can also use it wire up components to update automatically.
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>
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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!