Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
adg29 committed Nov 8, 2019
1 parent a40d3fe commit af666d9
Show file tree
Hide file tree
Showing 17 changed files with 318 additions and 2 deletions.
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

.vscode
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
# react-easy-peasy-typescript-hook-form
Created with CodeSandbox
# easy-peasy-typescript

This is an example implementation of using Typescript with [Easy Peasy](https://github.com/ctrlplusb/easy-peasy). This grants you a fully typed global state solution for React, which abstracts all of the Redux boilerplate whilst still granting you access to all of its power.

## Getting started

```
git clone https://github.com/ctrlplusb/easy-peasy-typescript
cd easy-peasy-typescript
npm install
npm start
```
37 changes: 37 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "easy-peasy-typescript-v3",
"version": "0.1.0",
"private": true,
"dependencies": {
"easy-peasy": "3.1.0",
"prop-types": "15.7.2",
"react": "16.11.0",
"react-dom": "16.11.0",
"react-hook-form": "3.26.5",
"react-scripts": "3.2.0"
},
"devDependencies": {
"@types/jest": "24.0.11",
"@types/node": "10.12.24",
"@types/react": "16.8.8",
"@types/react-dom": "16.8.2",
"typescript": "3.3.3333"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"keywords": [],
"description": "Official example of using Easy Peasy with Typescript"
}
Binary file added public/favicon.ico
Binary file not shown.
41 changes: 41 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Easy Peasy Typescript</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
15 changes: 15 additions & 0 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
21 changes: 21 additions & 0 deletions src/components/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { Component } from 'react';
import Todos from './todos';
import Notification from './notification';

class App extends Component {
render() {
return (
<div>
<h1>Easy Peasy + Typescript</h1>
<p>
This is a demonstration of how to utilise the Typescript integration
of <a href="https://github.com/ctrlplusb/easy-peasy">Easy Peasy</a>.
</p>
<Todos />
<Notification />
</div>
);
}
}

export default App;
23 changes: 23 additions & 0 deletions src/components/notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { useEffect } from "react";
import { useStoreState, useStoreActions } from "../hooks";

export default function Notification() {
// Pull the msg from store
const msg = useStoreState(state => state.notification.msg);

// Pull the set action from store
const set = useStoreActions(actions => actions.notification.set);

// We will reset the msg after 2s
useEffect(() => {
if (!msg) return;
const timeout = setTimeout(() => set(""), 2000);
return () => clearTimeout(timeout);
}, [msg, set]);

return (
<div style={{ position: "absolute", bottom: 10, right: 10, color: "blue" }}>
{msg}
</div>
);
}
33 changes: 33 additions & 0 deletions src/components/todos.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useState, useEffect } from "react";
import { useStoreActions, useStoreState } from "../hooks";

export default function Todos() {
// Pull out state from our store
const items = useStoreState(state => state.todos.items);

// Pull out actions from our store
const add = useStoreActions(actions => actions.todos.add);

// Track our form state
const [newTodo, setNewTodo] = useState("");

// Reset the form state every time the todo items changes
useEffect(() => setNewTodo(""), [items]);

return (
<div>
<h2>Todo List</h2>
<ul>
{items.map((todo, idx) => (
<li key={idx}>{todo}</li>
))}
</ul>
<input
type="text"
onChange={e => setNewTodo(e.target.value)}
value={newTodo}
/>
<button onClick={() => add(newTodo)}>Add</button>
</div>
);
}
10 changes: 10 additions & 0 deletions src/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createTypedHooks } from "easy-peasy";
import { StoreModel } from "./model";

const typedHooks = createTypedHooks<StoreModel>();

// We export the hooks from our store as they will contain the
// type information on them
export const useStoreActions = typedHooks.useStoreActions;
export const useStoreDispatch = typedHooks.useStoreDispatch;
export const useStoreState = typedHooks.useStoreState;
15 changes: 15 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import ReactDOM from "react-dom";
import { StoreProvider } from "easy-peasy";
import App from "./components/app";

import store from "./store";

import useForm from 'react-hook-form'

ReactDOM.render(
<StoreProvider store={store}>
<App />
</StoreProvider>,
document.getElementById("root")
);
14 changes: 14 additions & 0 deletions src/model/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import todos, { TodosModel } from './todos';
import notification, { NotificationModel } from './notification';

export interface StoreModel {
todos: TodosModel;
notification: NotificationModel;
}

const model: StoreModel = {
todos,
notification,
};

export default model;
25 changes: 25 additions & 0 deletions src/model/notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Action, action, Thunk, thunk } from "easy-peasy";
import todosModel from "./todos";

export interface NotificationModel {
msg: string;
set: Action<NotificationModel, string>;
onTodoAdded: Thunk<NotificationModel, string>;
}

const notification: NotificationModel = {
msg: "",
set: action((state, payload) => {
state.msg = payload;
}),
onTodoAdded: thunk(
(actions, payload) => {
actions.set(`Added "${payload}" to todos`);
},
{
listenTo: todosModel.add
}
)
};

export default notification;
15 changes: 15 additions & 0 deletions src/model/todos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Action, action } from 'easy-peasy';

export interface TodosModel {
items: string[];
add: Action<TodosModel, string>;
}

const todos: TodosModel = {
items: [],
add: action((state, payload) => {
state.items.push(payload);
}),
};

export default todos;
1 change: 1 addition & 0 deletions src/react-app-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="react-scripts" />
6 changes: 6 additions & 0 deletions src/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createStore } from 'easy-peasy';
import model from './model';

const store = createStore(model);

export default store;
25 changes: 25 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve"
},
"include": [
"src"
]
}

0 comments on commit af666d9

Please sign in to comment.