Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redux react hooks solution #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,24 @@ To demonstrate all kinds of ways to implement async with React & Redux.

If you like this repository, please :star: it and help to spread the word! :heart:


## Diffrent ways to implement async

1. [Writing Async Code Inline](./async-code-inline)
1. [Extracting Async Action Creator](./async-action-creator)
1. [Use Redux Thunk](./redux-thunk)
1. [Use Redux Saga](./redux-saga)
1. [Use Redux Logic](./redux-logic)

1. [Use Redux with React Hooks](./redux-react-hooks)

## Oncoming

1. [Use Redux Loop](https://github.com/redux-loop/redux-loop)


## My favorite solution isn't in the list

1. :fork_and_knife: Fork this project and submit a PR.
1. :point_right: [creating an issue](https://github.com/tylerlong/hello-async/issues/new?title=Could%20you%20please%20add%20a%20sample%20project%20for%20%3Cxxx%3E%20?).


## About the demo projects

In each demo project, we try to implement a notification feature:
Expand All @@ -33,7 +30,6 @@ In each demo project, we try to implement a notification feature:
- Each notification auto dismiss after 5 seconds.
- Multiple notifications are allowed simultaneously.


## Motivation

This repo is inspired by [this answer](http://stackoverflow.com/questions/35411423/how-to-dispatch-a-redux-action-with-a-timeout/35415559#35415559) on stackoverflow.
Expand All @@ -57,12 +53,11 @@ This repo is trying to add the missing things:
- Redux Logic
- ...


## How to run

Take [Writing Async Code Inline](./async-code-inline) for example:

```
```sh
git clone git@github.com:tylerlong/hello-async.git
cd hello-async/async-code-inline
yarn install
Expand Down
3 changes: 0 additions & 3 deletions async-code-inline/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@

This is by far the simplest way. Use what the language offers and go for the simplest solution.


## Pros

- Simple and straightforward.
- No middleware required.


## Cons

- React component contains business logic, bad for reusing. It's not obvious in this demo, but imagine we need to fetch data from server asynchronously.
- It forces you to duplicate this logic anywhere you want to show a notification.


## Notes

> Don’t use anything (including thunks) if you don’t have the genuine need for them. Remember that, depending on the requirements, your solution might look as simple as this project.
Expand Down
24 changes: 24 additions & 0 deletions redux-react-hooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Redux with React Hooks

Show the notification using Redux and React Hooks.

## Pros

- Simple and straightforward.
- No middleware required.

## Cons

- React component contains business logic, bad for reusing. It's not obvious in this demo, but imagine we need to fetch data from server asynchronously.
- It forces you to duplicate this logic anywhere you want to show a notification.
- Fails if component is unmounted.
- Less code and faster than class-based component
- No `connect` required

## Notes

> Don’t use anything (including thunks) if you don’t have the genuine need for them. Remember that, depending on the requirements, your solution might look as simple as this project.
>
> Don’t sweat it unless you know why you’re doing this.

Ref: http://stackoverflow.com/questions/35411423/how-to-dispatch-a-redux-action-with-a-timeout/35415559#35415559
21 changes: 21 additions & 0 deletions redux-react-hooks/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "hello-async",
"version": "0.1.0",
"private": true,
"devDependencies": {
"react-scripts": "0.8.4",
"standard": "^8.6.0"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.4",
"redux": "^4.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
Binary file added redux-react-hooks/public/favicon.ico
Binary file not shown.
31 changes: 31 additions & 0 deletions redux-react-hooks/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tag 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>React App</title>
</head>
<body>
<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`.
To create a production bundle, use `npm run build`.
-->
</body>
</html>
24 changes: 24 additions & 0 deletions redux-react-hooks/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.App {
text-align: center;
}

.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}

.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}

.App-intro {
font-size: large;
}

@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
45 changes: 45 additions & 0 deletions redux-react-hooks/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'

import logo from './logo.svg'
import './App.css'
import { showNotification, hideNotification } from './actions'

const App = () => {
const [nextNotificationId, setNextNotificationId] = useState(null)

const dispatch = useDispatch()

const notifications = useSelector(state => state.notifications)

function showNotificationWithTimeout (text) {
dispatch(showNotification(text, nextNotificationId + 1)).then(() => {
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
setNextNotificationId(nextNotificationId + 1)
})
}

return (
<div className='App'>
<div className='App-header'>
<img src={logo} className='App-logo' alt='logo' />
<h2>Welcome to React</h2>
</div>
<p className='App-intro'>
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<div>
<button onClick={() => showNotificationWithTimeout('Hello')}>Show "Hello"</button>
&nbsp;
<button onClick={() => showNotificationWithTimeout('Async')}>Show "Async"</button>
{notifications.map((notification) => {
return <h1 key={notification.id}>{notification.text}</h1>
})}
</div>
</div>
)
}

export default App
9 changes: 9 additions & 0 deletions redux-react-hooks/src/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const showNotification = (text, id) => {
return { type: 'SHOW_NOTIFICATION', text, id }
}

const hideNotification = (id) => {
return { type: 'HIDE_NOTIFICATION', id }
}

export { showNotification, hideNotification }
5 changes: 5 additions & 0 deletions redux-react-hooks/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
17 changes: 17 additions & 0 deletions redux-react-hooks/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'

import './index.css'
import App from './App'
import reducer from './reducers'

const store = createStore(reducer)

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
7 changes: 7 additions & 0 deletions redux-react-hooks/src/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions redux-react-hooks/src/reducers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { combineReducers } from 'redux'

const notifications = (state = [], action) => {
switch (action.type) {
case 'SHOW_NOTIFICATION':
return [...state, { id: action.id, text: action.text }]
case 'HIDE_NOTIFICATION':
return state.filter((notification) => notification.id !== action.id)
default:
return state
}
}

const combinedReducers = combineReducers({
notifications
})

export default combinedReducers
Loading