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 senkocalls 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)