Skip to content

Commit

Permalink
Rewrite Render so that it works with children
Browse files Browse the repository at this point in the history
  • Loading branch information
goatslacker committed Jul 14, 2015
1 parent e3a5b6b commit 784c76f
Show file tree
Hide file tree
Showing 9 changed files with 25,012 additions and 93 deletions.
24,163 changes: 24,163 additions & 0 deletions build.js

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import foo from './foo'
import Iso from 'iso'

Iso.bootstrap((state, meta, node) => {
console.log(meta)
foo.client(state, meta.props, node, meta.buffer)
})
182 changes: 182 additions & 0 deletions foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import Alt from './'
import React from 'react'
import Render, { connect } from './utils/Render'
import axios from 'axios'

const alt = new Alt()

const actions = alt.generateActions('yes', 'no')

const UserStore = alt.createStore(function () {
this.state = { users: [] }

this.bindAction(actions.yes, users => this.setState({ users }))
// this.bindAction(actions.yes, users => console.log('data', users))

this.exportPublicMethods({
getUsers: () => this.state.users,

fetchUsers: (user, repo) => {
return this.fetch({
remote() {
const url = `https://api.github.com/repos/${user}/${repo}/stargazers`
return axios({ url }).then(response => response.data)
},

success: actions.yes,
error: actions.no
})
}
})
}, 'UserStore')

@connect({
propTypes: {
user: React.PropTypes.string.isRequired,
repo: React.PropTypes.string.isRequired
},

listenTo() {
return [UserStore]
},

resolveAsync(props, context) {
return context.resolve(UserStore.fetchUsers, props.user, props.repo)
// return UserStore.fetchUsers(props.user, props.repo)
},

// reduceProps(props, context) {
// return {
// users: UserStore.getUsers()
// }
// },

// loading() {
// return <div>Loading...</div>
// },

failed(props, context) {
return <div>Uh oh</div>
}
})
class Stargazers extends React.Component {
static propTypes = {
users: React.PropTypes.array
}

render() {
return (
<section>
<div className="card">
<div className="card-content">
<span className="card-title deep-purple-text">Stargazers</span>
<p>
People who have starred this project
</p>
</div>
</div>

{this.renderUsers(this.props.users)}
</section>
)
}

renderUser(user) {
return (
<div key={user.id} style={{ display: 'inline-block' }}>
<img src={user.avatar_url} alt="" width={32} height={32} />
<br />
{user.login}
</div>
)
}

renderUsers(users) {
return (
<div>
{users.map(user => (
<div key={user.id}>
{this.renderUser(user)}
</div>
))}
</div>
)
}
}

@connect({
propTypes: {
user: React.PropTypes.string.isRequired,
repo: React.PropTypes.string.isRequired
},

listenTo() {
return [UserStore]
},

resolveAsync(props, context) {
return context.resolve(UserStore.fetchUsers, props.user, props.repo)
},

failed(props, context) {
return { users: [] }
}
})
class Count extends React.Component {
static propTypes = {
users: React.PropTypes.array
}

render() {
return <div>How many people? {this.props.users.length}</div>
}
}

class App extends React.Component {
constructor() {
super()
this.state = {
user: 'goatslacker',
repo: 'alt'
}

this.doChange = this.doChange.bind(this)
}

doChange() {
const user = this.refs.user.getDOMNode().value
const repo = this.refs.repo.getDOMNode().value

this.setState({ user, repo })
}

render() {
return (
<div>
<label>
User
<input type="text" ref="user" defaultValue={this.state.user} />
</label>
<label>
Repo
<input type="text" ref="repo" defaultValue={this.state.repo} />
</label>
<button onClick={this.doChange}>Go</button>
<Count user={this.state.user} repo={this.state.repo} />
<Stargazers user={this.state.user} repo={this.state.repo} />
</div>
)
}
}

export default {
server(props) {
console.log('Requesting', props)
return new Render(alt).toString(App, props)
},

client(state, props, node, meta) {
alt.bootstrap(state)
new Render(alt).toDOM(App, props, node, meta)
}
}
41 changes: 41 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import express from 'express'
import foo from './foo'
import Iso from 'iso'

const app = express()

app.get('/', (req, res) => {
const props = {}

foo.server(props).then((obj) => {
console.log('Server done...', obj)
const html = Iso.render(obj.html, obj.state, {
props,
buffer: obj.buffer
})

if (obj.error) console.log(obj.error.stack)

res.send(`
<html>
<head></head>
<body>
${html}
</body>
<script src="/build.js"></script>
</html>
`)
}).catch((e) => {
res.send(`:(<br />${e.stack}`)
})
})

import fs from 'fs'

const buildjs = fs.readFileSync('./build.js')

app.get('/build.js', (req, res) => {
res.send(buildjs)
})

app.listen(3000, stat => console.log('Listening', 3000))
34 changes: 34 additions & 0 deletions src/alt/store/StoreMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,40 @@ const StoreMixin = {
})
},

fetch(spec) {
const validHandlers = ['success', 'error', 'loading']
validHandlers.forEach((handler) => {
if (spec[handler] && !spec[handler].id) {
throw new Error(`${handler} handler must be an action function`)
}
})

const value = spec.local && spec.local()
const shouldFetch = spec.shouldFetch
? spec.shouldFetch()
: value == null

const intercept = spec.interceptResponse || (x => x)

const handleAction = (action, x) => {
const fire = () => action(intercept(x, action))
return this.alt.trapAsync ? (() => fire()) : fire()
}

// if we don't have it in cache then fetch it
if (shouldFetch) {
/* istanbul ignore else */
if (spec.loading) spec.loading(intercept(null, spec.loading))
return spec.remote().then(
x => Promise.resolve(handleAction(spec.success, x)),
e => Promise.reject(handleAction(spec.error, e))
)
} else {
// otherwise emit the change now
this.emitChange()
}
},

exportPublicMethods(methods) {
fn.eachObject((methodName, value) => {
if (!fn.isFunction(value)) {
Expand Down
28 changes: 17 additions & 11 deletions src/utils/AltIso.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
import Iso from 'iso'
import * as Render from './Render'
import Render from './Render'

export default {
define: Render.withData,
define: Render.resolve,
resolve: Render.resolve,

render(alt, Component, props) {
if (typeof window === 'undefined') {
return Render.toString(alt, Component, props).then((obj) => {
return new Render(alt).toString(Component, props).then((obj) => {
return {
html: Iso.render(obj.html, obj.state, { iso: 1 })
html: Iso.render(obj.html, obj.state, obj.buffer)
}
}).catch((err) => {
// return the empty markup in html when there's an error
return {
err,
html: Iso.render()
}).catch(
/* istanbul ignore next */
(err) => {
// this is a fail-safe case you should never hit. In case there's an
// error flushing alt or something blows up then we should render
// empty markup so that we can bootstrap anyway and render client side.
return {
err,
html: Iso.render()
}
}
})
)
} else {
Iso.bootstrap((state, meta, node) => {
alt.bootstrap(state)
Render.toDOM(Component, props, node, meta.iso)
new Render(alt).toDOM(Component, props, node, meta)
})
return Promise.resolve()
}
Expand Down
Loading

0 comments on commit 784c76f

Please sign in to comment.