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)