Senko - easy global state in react
Tags: react, showdev, webdev, typescript
Published: 2021-04-25 03:35:23

# 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:*

```ts
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!

[**Github**](https://github.com/raghav-misra/senko) | [`npm i senko`](https://www.npmjs.com/package/senko)

## 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

1. Delete everything in `/src`
2. 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.

```ts
// 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:

```ts
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.

```ts
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.

```ts
function Form() {
	const store = useStore(); // we imported this before

	/* omitted for brevity */
}
```
Usually, a two-way binding would like this:

```ts
<input 
	value={store.username} 
	onInput={e => store.username = e.target.value} 
/>
```

However, with a Senko store, you can use our two-way binding helper:

```ts
<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:

```ts
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!

```ts
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.

https://github.com/raghav-misra/senko-demo