Skip to content

Commit 4351095

Browse files
committed
Added redux todo example
1 parent 2aa913a commit 4351095

File tree

13 files changed

+284
-1
lines changed

13 files changed

+284
-1
lines changed

examples/README.MD

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# `react-concise-state` examples
22

3-
* [Simple counter](/examples/counter) | Try it in a [sandbox ✏️](https://codesandbox.io/s/github/minajevs/react-concise-state/tree/master/examples/counter)
3+
* [Simple counter](/examples/counter) | Try it in a [sandbox ✏️](https://codesandbox.io/s/github/minajevs/react-concise-state/tree/master/examples/counter)
4+
* [Simple todo](/examples/todo) | Compare with [redux implementation](https://redux.js.org/basics/example) | Try it in a [sandbox ✏️](https://codesandbox.io/s/github/minajevs/react-concise-state/tree/master/examples/todo)

examples/todo/package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "new",
3+
"version": "1.0.0",
4+
"description": "",
5+
"keywords": [],
6+
"main": "src/index.tsx",
7+
"dependencies": {
8+
"react": "16.8.4",
9+
"react-concise-state": "0.4.0",
10+
"react-dom": "16.8.4",
11+
"react-scripts": "2.1.3"
12+
},
13+
"devDependencies": {
14+
"@types/react": "16.8.8",
15+
"@types/react-dom": "16.8.2",
16+
"typescript": "3.3.3"
17+
},
18+
"scripts": {
19+
"start": "react-scripts start",
20+
"build": "react-scripts build",
21+
"test": "react-scripts test --env=jsdom",
22+
"eject": "react-scripts eject"
23+
},
24+
"browserslist": [
25+
">0.2%",
26+
"not dead",
27+
"not ie <= 11",
28+
"not op_mini all"
29+
]
30+
}

examples/todo/public/index.html

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7+
<meta name="theme-color" content="#000000">
8+
<!--
9+
manifest.json provides metadata used when your web app is added to the
10+
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
11+
-->
12+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
13+
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
14+
<!--
15+
Notice the use of %PUBLIC_URL% in the tags above.
16+
It will be replaced with the URL of the `public` folder during the build.
17+
Only files inside the `public` folder can be referenced from the HTML.
18+
19+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
20+
work correctly both with client-side routing and a non-root public URL.
21+
Learn how to configure a non-root public URL by running `npm run build`.
22+
-->
23+
<title>React App</title>
24+
</head>
25+
26+
<body>
27+
<noscript>
28+
You need to enable JavaScript to run this app.
29+
</noscript>
30+
<div id="root"></div>
31+
<!--
32+
This HTML file is a template.
33+
If you open it directly in the browser, you will see an empty page.
34+
35+
You can add webfonts, meta tags, or analytics to this file.
36+
The build step will place the bundled scripts into the <body> tag.
37+
38+
To begin the development, run `npm start` or `yarn start`.
39+
To create a production bundle, use `npm run build` or `yarn build`.
40+
-->
41+
</body>
42+
43+
</html>

examples/todo/src/AddTodo.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from 'react'
2+
3+
import { context } from './tabStore'
4+
5+
const AddTodo: React.FC = props => {
6+
const store = React.useContext(context)
7+
let input
8+
return (
9+
<div>
10+
<form
11+
onSubmit={e => {
12+
e.preventDefault()
13+
if (!input.value.trim()) {
14+
return
15+
}
16+
store.addTodo(input.value)
17+
input.value = ''
18+
}}
19+
>
20+
<input ref={node => (input = node)} />
21+
<button type="submit">Add Todo</button>
22+
</form>
23+
</div>
24+
)
25+
}
26+
27+
export default AddTodo

examples/todo/src/App.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from 'react'
2+
3+
import { Provider as TabProvider } from './tabStore'
4+
import { Provider as VisibilityProvider } from './visibilityStore'
5+
6+
import AddTodo from './AddTodo'
7+
import TodoList from './TodoList'
8+
import Footer from './Footer'
9+
10+
const App: React.FC = props => (
11+
<VisibilityProvider>
12+
<TabProvider>
13+
<AddTodo />
14+
<TodoList />
15+
<Footer />
16+
</TabProvider>
17+
</VisibilityProvider>
18+
)
19+
20+
export default App

examples/todo/src/FilterLink.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as React from 'react'
2+
3+
import { context, VisibilityFilter } from './visibilityStore'
4+
5+
type Props = {
6+
filter: VisibilityFilter
7+
}
8+
9+
const FilterLink: React.FC<Props> = ({ filter, children }) => {
10+
const store = React.useContext(context)
11+
12+
return (
13+
<button
14+
onClick={() => store.setFilter(filter)}
15+
disabled={store.filter === filter}
16+
style={{
17+
marginLeft: '4px'
18+
}}
19+
>
20+
{children}
21+
</button>
22+
)
23+
}
24+
25+
export default FilterLink

examples/todo/src/Footer.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as React from 'react'
2+
3+
import FilterLink from './FilterLink'
4+
import { VisibilityFilter } from './visibilityStore'
5+
6+
const Footer = () => (
7+
<div>
8+
<span>Show: </span>
9+
<FilterLink filter={VisibilityFilter.SHOW_ALL}>All</FilterLink>
10+
<FilterLink filter={VisibilityFilter.SHOW_ACTIVE}>Active</FilterLink>
11+
<FilterLink filter={VisibilityFilter.SHOW_COMPLETED}>Completed</FilterLink>
12+
</div>
13+
)
14+
15+
export default Footer

examples/todo/src/Todo.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import * as React from 'react'
2+
3+
const Todo = ({ onClick, completed, text }) => (
4+
<li
5+
onClick={onClick}
6+
style={{
7+
textDecoration: completed ? 'line-through' : 'none'
8+
}}
9+
>
10+
{text}
11+
</li>
12+
)
13+
14+
export default Todo

examples/todo/src/TodoList.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as React from 'react'
2+
3+
import { context as tabContext, Todo as TodoModel } from './tabStore'
4+
import {
5+
context as visibilityContext,
6+
VisibilityFilter
7+
} from './visibilityStore'
8+
import Todo from './Todo'
9+
10+
const getVisibleTodos = (todos: TodoModel[], filter: VisibilityFilter) => {
11+
switch (filter) {
12+
case VisibilityFilter.SHOW_ALL:
13+
return todos
14+
case VisibilityFilter.SHOW_COMPLETED:
15+
return todos.filter(t => t.completed)
16+
case VisibilityFilter.SHOW_ACTIVE:
17+
return todos.filter(t => !t.completed)
18+
default:
19+
throw new Error('Unknown filter: ' + filter)
20+
}
21+
}
22+
23+
const TodoList: React.FC = props => {
24+
const { todos, toggleTodo } = React.useContext(tabContext)
25+
const { filter } = React.useContext(visibilityContext)
26+
27+
const visibleTodos = getVisibleTodos(todos, filter)
28+
29+
return (
30+
<ul>
31+
{visibleTodos.map(todo => (
32+
<Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} />
33+
))}
34+
</ul>
35+
)
36+
}
37+
38+
export default TodoList

examples/todo/src/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as React from 'react'
2+
3+
import { render } from 'react-dom'
4+
5+
import App from './App'
6+
7+
const rootElement = document.getElementById('root')
8+
render(<App />, rootElement)

0 commit comments

Comments
 (0)