Straightforward global state in React.
This project is a work-in-progress, so feel free to contribute. :D
Feedback much, much appreciated!
Why Senko?
When writing React apps, global state management becomes a larger concern than it should be. Enter Senko, an easy state management solution with a lot of power.
Let's look at a simple example:
import React from "react";
import senko from "senko";
const useStore = senko({ count: 0 });
function Counter() {
const store = useStore();
return <>
<code>{store.count}</code>
<button onClick={() => store.count++}>up</button>
<button onClick={() => store.count--}>down</button>
</>;
}
The useStore
hook that is returned from the senko(...)
call can be called from any component, and they will all refer to the same state.
Features:
- First-class Typescript support
(like really first class). - Multiple
senko
calls can be used to make isolated stores that can then be used in any component. - Really straightforward, no top-level provider wrappers, etc.
Check it out!
Let's build an example:
Scaffold an app with CRA
npx create-react-app senko-test --template=typescript
(feel free to follow along with JS instead)
Restructure files & folders
- Delete everything in
/src
- Create the following files in
/src
:index.tsx
store.ts
yarn add senko
No senko app is complete without senko!
Write the store
Inside store.ts
, throw the following.
I've added comments to walk you through it.
// No senko app is complete without senko!
import senko from "senko";
// We're gonna have a signup form:
// Pass in the initial state to the senko function:
export const useStore = senko({
username: "",
email: "",
password: ""
});
// Oh also you can use a default export instead,
// I'm just not a big fan xD.
Write the frontend
Okay, now that the store is done, we can write the actual React code.
Here's a template so you don't need to write the small stuff:
import React from "react";
import ReactDOM from "react-dom";
import { useStore } from "./store";
function Form() {
}
ReactDOM.render(<Form />, document.querySelector("#root"));
Now, we have the basic stuff in place, let's dive into writing the Form
component.
function Form() {
return (
<form>
<label>Username:</label>
<input
type="text"
placeholder="CoolGuy1234"
/>
<label>Email:</label>
<input
type="email"
placeholder="coolguy1234@gmail.io"
/>
<label>Password:</label>
<input
type="password"
placeholder="Shhhhhhhhh!"
/>
<button type="submit">Signup!</button>
</form>
);
}
There's our form structure (not a great-looking one, but it's there).
Two-way binding
Now let's look at binding these inputs to the store.
function Form() {
const store = useStore(); // we imported this before
/* omitted for brevity */
}
Usually, a two-way binding would like this:
<input
value={store.username}
onInput={e => store.username = e.target.value}
/>
However, with a Senko store, you can use our two-way binding helper:
<input {...store.model.username()} />
Basically use store.model.thePropYouWantToBindTo
(in our case: username
, email
, and password
).
These bindings in our Form
component would look like:
function Form() {
const store = useStore();
return (
<form>
<label>Username:</label>
<input
type="text"
placeholder="CoolGuy1234"
{...store.model.username()}
/>
<label>Email:</label>
<input
type="email"
placeholder="coolguy1234@gmail.io"
{...store.model.email()}
/>
<label>Password:</label>
<input
type="password"
placeholder="Shhhhhhhhh!"
{...store.model.password()}
/>
<button type="submit">Signup!</button>
</form>
);
}
Finishing up
How do we know this two-way binding actually works?
Let's add a submit
event to our form and prove it!
function Form() {
const store = useStore();
const onLogin: React.FormEventHandler = (e) => {
e.preventDefault();
console.log(
"You signed up with the username:",
store.username,
"\nThe email:",
store.email,
"\nAnd your password was supposed to be secret but we don't care:",
store.password
);
};
return (
<form onSubmit={onLogin}>
{/* omitted for brevity */}
</form>
);
}
Try it out
Keep adding different values to the inputs and hitting submit!
You should see updated values everytime.
Farewell!
Thanks for reading this far! :D
Hope you enjoyed this post, a reaction or feedback would be much appreciated.
Top comments (0)