-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d3eed7a
commit 2fdaaf1
Showing
11 changed files
with
388 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
{ | ||
"presets": ["env"] | ||
"presets": ["env", "react"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`ReComponent with Immutable.JS records increases the counter when clicked 1`] = ` | ||
<button> | ||
You've clicked this | ||
1 | ||
times(s) | ||
</button> | ||
`; | ||
|
||
exports[`ReComponent with Immutable.JS records renders the initial state 1`] = ` | ||
<button> | ||
You've clicked this | ||
0 | ||
times(s) | ||
</button> | ||
`; | ||
|
||
exports[`ReComponent with mocked console errors when no \`reducer\` method is defined 1`] = `"Example(...): No \`reducer\` method found on the returned component instance: did you define a reducer?"`; | ||
|
||
exports[`ReComponent with plain JS objects increases the counter when clicked 1`] = ` | ||
<button> | ||
You've clicked this | ||
1 | ||
times(s) | ||
</button> | ||
`; | ||
|
||
exports[`ReComponent with plain JS objects renders the initial state 1`] = ` | ||
<button> | ||
You've clicked this | ||
0 | ||
times(s) | ||
</button> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,117 @@ | ||
import { PID, spawn, isAlive, self, receive, send } from "../"; | ||
import React from "react"; | ||
import ReactDOM from "react-dom"; | ||
import { Record } from "immutable"; | ||
|
||
describe("process", () => { | ||
describe("spawn", () => { | ||
it("runs the process", done => { | ||
spawn(function* () { done() }); | ||
import { ReComponent } from "../"; | ||
|
||
global.__DEV__ = true; | ||
|
||
function click(element) { | ||
element.dispatchEvent(new Event("click", { bubbles: true })); | ||
} | ||
|
||
describe("ReComponent", () => { | ||
let container; | ||
beforeEach(() => { | ||
container = document.createElement("div"); | ||
document.body.appendChild(container); | ||
}); | ||
|
||
describe("with plain JS objects", () => { | ||
class Example extends ReComponent { | ||
constructor() { | ||
super(); | ||
this.handleClick = this.createDispatcher("CLICK"); | ||
} | ||
|
||
initialState(props) { | ||
return { | ||
count: 0 | ||
}; | ||
} | ||
|
||
reducer(action, state) { | ||
switch (action.type) { | ||
case "CLICK": | ||
return { count: state.count + 1 }; | ||
} | ||
} | ||
|
||
render() { | ||
return ( | ||
<button onClick={this.handleClick}> | ||
You've clicked this {this.state.count} times(s) | ||
</button> | ||
); | ||
} | ||
} | ||
|
||
it("renders the initial state", () => { | ||
const instance = ReactDOM.render(<Example />, container); | ||
expect(container.firstChild).toMatchSnapshot(); | ||
}); | ||
|
||
it("returns a pid", () => { | ||
const pid = spawn(function* () {}); | ||
expect(pid).toBeInstanceOf(PID); | ||
it("increases the counter when clicked", () => { | ||
const instance = ReactDOM.render(<Example />, container); | ||
click(container.firstChild); | ||
expect(container.firstChild).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
||
describe("isAlive", () => { | ||
it("returns true for another process", () => { | ||
const pid = spawn(function* () { return }); | ||
expect(isAlive(pid)).toBe(true); | ||
describe("with Immutable.JS records", () => { | ||
const State = Record({ count: 0 }); | ||
class Example extends ReComponent { | ||
constructor() { | ||
super(); | ||
this.handleClick = this.createDispatcher("CLICK"); | ||
} | ||
|
||
initialState(props) { | ||
return State(); | ||
} | ||
|
||
reducer(action, state) { | ||
switch (action.type) { | ||
case "CLICK": | ||
return state.update("count", count => count + 1); | ||
} | ||
} | ||
|
||
render() { | ||
return ( | ||
<button onClick={this.handleClick}> | ||
You've clicked this {this.immutableState.count} times(s) | ||
</button> | ||
); | ||
} | ||
} | ||
|
||
it("renders the initial state", () => { | ||
const instance = ReactDOM.render(<Example />, container); | ||
expect(container.firstChild).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
||
describe("send and receive", () => { | ||
it("can receive a messages on the main process that was already sent", async () => { | ||
send(self(), { | ||
type: "test", | ||
payload: { key: "value" } | ||
}); | ||
|
||
const message = await receive("test"); | ||
expect(message).toEqual({ | ||
type: "test", | ||
payload: { key: "value" } | ||
}); | ||
it("increases the counter when clicked", () => { | ||
const instance = ReactDOM.render(<Example />, container); | ||
click(container.firstChild); | ||
expect(container.firstChild).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
||
it("can receive a messages on the main process that will be sent", async () => { | ||
setTimeout(() => { | ||
send(self(), { | ||
type: "test", | ||
payload: { key: "value" } | ||
}); | ||
}, 0); | ||
|
||
const message = await receive("test"); | ||
expect(message).toEqual({ | ||
type: "test", | ||
payload: { key: "value" } | ||
}); | ||
describe("with mocked console", () => { | ||
const originalError = console.error; | ||
beforeEach(() => (console.error = jest.fn())); | ||
afterEach(() => (console.error = originalError)); | ||
it("errors when no `reducer` method is defined", () => { | ||
class Example extends ReComponent { | ||
render() { | ||
return <div />; | ||
} | ||
} | ||
|
||
expect(() => { | ||
ReactDOM.render(<Example />, container); | ||
}).toThrowErrorMatchingSnapshot(); | ||
}); | ||
}); | ||
}); | ||
|
||
// class CountServer extends GenServer { | ||
// getInitialState(initialProps) { | ||
// this.state = { counter: initialProps.counter || 0 } | ||
// } | ||
|
||
// // async | ||
// handleCast(action) { | ||
// switch (action.type) { | ||
// case "INCREMENT": | ||
// this.setState(({ count }) => { | ||
// count: count + 1; | ||
// }); | ||
// break; | ||
// case "DECREMENT": | ||
// this.setState(({ count }) => { | ||
// count: count - 1; | ||
// }); | ||
// break; | ||
// } | ||
// } | ||
|
||
// // sync | ||
// handleCall(action) { | ||
// switch (action.type) { | ||
// case "INCREMENT": | ||
// this.setState(({ count }) => { | ||
// count: count + 1; | ||
// }); | ||
// break; | ||
// case "DECREMENT": | ||
// this.setState(({ count }) => { | ||
// count: count - 1; | ||
// }); | ||
// break; | ||
// } | ||
// } | ||
// } | ||
// | ||
// describe("react-genserver", () => { | ||
// it("works", () => { | ||
// const pid = start(CountServer) | ||
// console.log(pid); | ||
// }); | ||
// }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,20 @@ | ||
{ | ||
"name": "react-genserver", | ||
"version": "1.0.0", | ||
"name": "react-recomponent", | ||
"version": "0.0.1", | ||
"main": "src/index.js", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"babel-core": "^6.26.3", | ||
"babel-jest": "^23.0.1", | ||
"babel-preset-env": "^1.7.0", | ||
"babel-preset-react": "^6.24.1", | ||
"jest": "^23.1.0", | ||
"prettier": "^1.13.4" | ||
"prettier": "^1.13.4", | ||
"react": "^16.4.0", | ||
"react-dom": "^16.4.0", | ||
"react-test-renderer": "^16.4.0" | ||
}, | ||
"dependencies": { | ||
"erlang-processes": "^2.0.0", | ||
"erlang-types": "^1.0.1" | ||
"peerDependencies": { | ||
"react": "^16.4.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,55 @@ | ||
// export { self } from './pid' | ||
export { start, self, spawn, send, receive, isAlive } from "./process"; | ||
import React from "react"; | ||
|
||
export {PID } from "erlang-types" | ||
// export class GenServer { | ||
// constructor(initialProps) { | ||
// this.getInitialState && this.setState(this.getInitialState(initialProps)); | ||
// } | ||
import { isImmutable } from "./isImmutable"; | ||
|
||
// setState(updater) { | ||
// let nextState = updater; | ||
// if (typeof updater == "function") { | ||
// nextState = updater(this.state); | ||
// } | ||
export class ReComponent extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
// this.state = Object.assign({}, this.state, nextState); | ||
// } | ||
if (__DEV__) { | ||
if(typeof this.reducer !== 'function') { | ||
const name = this.constructor.name || this.displayName | ||
throw new Error(name + '(...): No `reducer` method found on the returned component ' + | ||
'instance: did you define a reducer?') | ||
} | ||
} | ||
|
||
// cast() {} | ||
let stateIsImmutable = false; | ||
if (this.initialState) { | ||
let initialState = this.initialState(props); | ||
|
||
// call() {} | ||
// } | ||
if (isImmutable(initialState)) { | ||
stateIsImmutable = true; | ||
initialState = { immutableState: initialState }; | ||
|
||
// export { start, spawn, send, receive }; | ||
// Define Immutable.js helpers | ||
this.setImmutableState = updater => { | ||
this.setState({ immutableState: updater(this.immutableState) }); | ||
}; | ||
Object.defineProperty(this, "immutableState", { | ||
get: () => this.state.immutableState | ||
}); | ||
} | ||
|
||
this.state = initialState; | ||
} | ||
|
||
this.send = action => { | ||
const reduce = state => this.reducer(action, state) | ||
|
||
if (stateIsImmutable) { | ||
this.setImmutableState(reduce); | ||
} else { | ||
this.setState(reduce); | ||
} | ||
}; | ||
|
||
this.createDispatcher = type => { | ||
return payload => | ||
this.send({ | ||
type, | ||
payload | ||
}); | ||
}; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* Copyright (c) 2014-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @see https://github.com/facebook/immutable-js/blob/v4.0.0-rc.9/src/Predicates.js | ||
*/ | ||
|
||
export function isImmutable(maybeImmutable) { | ||
return isCollection(maybeImmutable) || isRecord(maybeImmutable); | ||
} | ||
|
||
function isCollection(maybeCollection) { | ||
return !!(maybeCollection && maybeCollection[IS_ITERABLE_SENTINEL]); | ||
} | ||
|
||
function isRecord(maybeRecord) { | ||
return !!(maybeRecord && maybeRecord[IS_RECORD_SENTINEL]); | ||
} | ||
|
||
export const IS_ITERABLE_SENTINEL = "@@__IMMUTABLE_ITERABLE__@@"; | ||
export const IS_RECORD_SENTINEL = "@@__IMMUTABLE_RECORD__@@"; |
Oops, something went wrong.