mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Example: with Freactal (#2955)
* Define dependencies & NPM stuff for the example * Setup Babel preset * Add sources of working version of example * Indicate ajax loading state * Add readme file * Remove unneeded .babelrc
This commit is contained in:
parent
093b091a5c
commit
d03ce5386d
39
examples/with-freactal/README.md
Normal file
39
examples/with-freactal/README.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-freactal)
|
||||
|
||||
# Freactal example
|
||||
|
||||
## How to use
|
||||
|
||||
Download the example [or clone the repo](https://github.com/zeit/next.js):
|
||||
|
||||
```bash
|
||||
curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-freactal
|
||||
cd with-freactal
|
||||
```
|
||||
|
||||
Install it and run:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
|
||||
|
||||
```bash
|
||||
now
|
||||
```
|
||||
|
||||
## The idea behind the example
|
||||
|
||||
When it comes to state management of the React webapp, Redux is the most popular solution. However it brings lots of boilerplate code and fiddling aroud multiple files when tracing even simplest state change.
|
||||
|
||||
[Freactal](https://github.com/FormidableLabs/freactal) is a state management library that put this disadvantages away. With very little setup code your components' `props` are enhanced with two key ingredients: `state` and `effects`. Another benefit of Freactal is that you don't need to place *state* at some special place (global store). You can even have multiple state roots and compose them together - just like your components (this is true also for `effects`).
|
||||
|
||||
### example app
|
||||
|
||||
In this example the `index` page renders list of public repos on Github for selected username. It fetches list of repos from public gihub api. First page of this list is rendered by SSR. *serverState* is then hydrated into the `Index` page. Button at the end of the list allows to load next page of repos list from the API on the client.
|
||||
|
||||
![](https://i.imgur.com/JFU0YUt.png)
|
||||
|
||||
For simplicity the last page is not handled.
|
30
examples/with-freactal/components/app.js
Normal file
30
examples/with-freactal/components/app.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import React from 'react'
|
||||
import { fetchUserRepos } from '../githubApi'
|
||||
import provideStateFactory from '../provideState'
|
||||
|
||||
export default (Page) => {
|
||||
const App = ({ serverState }) => {
|
||||
const withState = provideStateFactory(serverState)
|
||||
const PageWithState = withState(Page)
|
||||
|
||||
return <PageWithState />
|
||||
}
|
||||
|
||||
App.getInitialProps = async () => {
|
||||
const username = 'arunoda'
|
||||
const page = 1
|
||||
const repos = await fetchUserRepos(username, page)
|
||||
|
||||
return {
|
||||
serverState: {
|
||||
githubReposList: {
|
||||
username,
|
||||
page,
|
||||
repos
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return App
|
||||
}
|
8
examples/with-freactal/githubApi.js
Normal file
8
examples/with-freactal/githubApi.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* global fetch */
|
||||
import 'isomorphic-fetch'
|
||||
|
||||
const API_BASE_URL = 'https://api.github.com'
|
||||
|
||||
export const fetchUserRepos = (username, page = 1) =>
|
||||
fetch(`${API_BASE_URL}/users/${username}/repos?page=${page}`)
|
||||
.then(response => response.json())
|
17
examples/with-freactal/package.json
Normal file
17
examples/with-freactal/package.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "with-freactal",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"freactal": "^1.1.1",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"next": "latest",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1"
|
||||
},
|
||||
"license": "ISC"
|
||||
}
|
46
examples/with-freactal/pages/index.js
Normal file
46
examples/with-freactal/pages/index.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
import React from 'react'
|
||||
import { injectState } from 'freactal'
|
||||
import app from '../components/app'
|
||||
|
||||
const Index = injectState(({ state: { ajaxStatus, githubReposList }, effects }) => {
|
||||
const fetchMore = () =>
|
||||
effects.fetchGithubReposList(githubReposList.username, githubReposList.page + 1)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{`List of @${githubReposList.username}'s repositories`}</h1>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>name</th>
|
||||
<th>watchers</th>
|
||||
<th>stars</th>
|
||||
<th>forks</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{githubReposList.repos.map((repo) => (
|
||||
<tr key={repo.id}>
|
||||
<td>{repo.name}</td>
|
||||
<td>{repo.watchers_count}</td>
|
||||
<td>{repo.stargazers_count}</td>
|
||||
<td>{repo.forks_count}</td>
|
||||
</tr>
|
||||
))}
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td colSpan='3'>
|
||||
<button
|
||||
onClick={fetchMore}
|
||||
disabled={ajaxStatus}
|
||||
>{ajaxStatus ? 'loading' : 'fetch more'}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default app(Index)
|
26
examples/with-freactal/provideState.js
Normal file
26
examples/with-freactal/provideState.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { provideState, update } from 'freactal'
|
||||
import { fetchUserRepos } from './githubApi'
|
||||
|
||||
export default serverState => provideState({
|
||||
initialState: () => ({
|
||||
...serverState,
|
||||
ajaxStatus: false
|
||||
}),
|
||||
|
||||
effects: {
|
||||
setAjaxLoader: update((state, ajaxStatus) => ({ ajaxStatus })),
|
||||
|
||||
fetchGithubReposList: (effects, username, page) =>
|
||||
effects.setAjaxLoader(true)
|
||||
.then(() => fetchUserRepos(username, page))
|
||||
.then((repos) => effects.setAjaxLoader(false).then(() => repos))
|
||||
.then((repos) => (state) => ({
|
||||
...state,
|
||||
githubReposList: {
|
||||
username,
|
||||
page,
|
||||
repos: state.githubReposList.repos.concat(repos)
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
Loading…
Reference in a new issue