Skip to content

Commit 9962ee7

Browse files
committed
Cleans up project, removing unneeded/unused code.
Refactors SSR state rehydration. It is now your responsibility to return and bind it to the client rendered `AsyncComponentsProvider`, via the `initialState` prop.
1 parent cfeb2b1 commit 9962ee7

File tree

10 files changed

+81
-91
lines changed

10 files changed

+81
-91
lines changed

src/AsyncComponentProvider.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ import React from 'react'
33
import createContext from './createContext'
44

55
class AsyncComponentProvider extends React.Component {
6-
constructor(props, context) {
7-
super(props, context)
8-
9-
this.execContext = props.execContext || createContext()
6+
componentWillMount() {
7+
this.execContext = this.props.execContext || createContext()
8+
this.rehydrateState = this.props.initialState
109
}
1110

1211
getChildContext() {
@@ -17,6 +16,17 @@ class AsyncComponentProvider extends React.Component {
1716
getComponent: this.execContext.getComponent,
1817
registerError: this.execContext.registerError,
1918
getError: this.execContext.getError,
19+
getRehydrate: (id) => {
20+
const error = this.rehydrateState.errors[id]
21+
const resolved = this.rehydrateState.resolved[id]
22+
delete this.rehydrateState.errors[id]
23+
delete this.rehydrateState.resolved[id]
24+
return {
25+
// eslint-disable-next-line no-nested-ternary
26+
type: error ? 'error' : resolved ? 'resolved' : 'unresolved',
27+
error,
28+
}
29+
},
2030
},
2131
}
2232
}
@@ -35,10 +45,18 @@ AsyncComponentProvider.propTypes = {
3545
registerError: React.PropTypes.func.isRequired,
3646
getError: React.PropTypes.func.isRequired,
3747
}),
48+
initialState: React.PropTypes.shape({
49+
resolved: React.PropTypes.object,
50+
errors: React.PropTypes.object,
51+
}),
3852
}
3953

4054
AsyncComponentProvider.defaultProps = {
4155
execContext: undefined,
56+
initialState: {
57+
resolved: {},
58+
errors: {},
59+
},
4260
}
4361

4462
AsyncComponentProvider.childContextTypes = {
@@ -48,6 +66,7 @@ AsyncComponentProvider.childContextTypes = {
4866
getComponent: React.PropTypes.func.isRequired,
4967
registerError: React.PropTypes.func.isRequired,
5068
getError: React.PropTypes.func.isRequired,
69+
getRehydrate: React.PropTypes.func.isRequired,
5170
}).isRequired,
5271
}
5372

src/__tests__/__snapshots__/integration.test.js.snap

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ exports[`integration tests render server and client 3`] = `
2727
"registerError": [Function],
2828
}
2929
}
30+
initialState={
31+
Object {
32+
"errors": Object {},
33+
"resolved": Object {},
34+
}
35+
}
3036
>
3137
<AsyncBob>
3238
<Bob>
@@ -86,6 +92,12 @@ exports[`integration tests render server and client 4`] = `
8692
"registerError": [Function],
8793
}
8894
}
95+
initialState={
96+
Object {
97+
"errors": Object {},
98+
"resolved": Object {},
99+
}
100+
}
89101
>
90102
<AsyncBob>
91103
<Bob>
@@ -155,6 +167,12 @@ exports[`integration tests renders the ErrorComponent 1`] = `
155167
"registerError": [Function],
156168
}
157169
}
170+
initialState={
171+
Object {
172+
"errors": Object {},
173+
"resolved": Object {},
174+
}
175+
}
158176
>
159177
<AsyncComponent>
160178
<ErrorComponent
@@ -180,6 +198,12 @@ exports[`integration tests renders the LoadingComponent 1`] = `
180198
"registerError": [Function],
181199
}
182200
}
201+
initialState={
202+
Object {
203+
"errors": Object {},
204+
"resolved": Object {},
205+
}
206+
}
183207
>
184208
<AsyncComponent>
185209
<LoadingComponent>

src/__tests__/integration.test.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
createContext,
88
createAsyncComponent,
99
asyncBootstrapper,
10-
STATE_IDENTIFIER,
1110
} from '../'
1211

1312
function Bob({ children }) {
@@ -54,8 +53,11 @@ const ErrorAsyncComponent = createAsyncComponent({
5453
ErrorComponent: ({ message }) => <div>{message}</div>,
5554
})
5655

57-
const createApp = execContext => (
58-
<AsyncComponentProvider execContext={execContext}>
56+
const createApp = (execContext, stateForClient) => (
57+
<AsyncComponentProvider
58+
execContext={execContext}
59+
initialState={stateForClient}
60+
>
5961
<AsyncBob>
6062
<div>
6163
<AsyncBobTwo>
@@ -79,13 +81,9 @@ const createApp = execContext => (
7981
)
8082

8183
describe('integration tests', () => {
82-
afterEach(() => {
83-
delete global.window[STATE_IDENTIFIER]
84-
})
85-
8684
it('render server and client', () => {
87-
const windowTemp = global.window
8885
// we have to delete the window to emulate a server only environment
86+
const windowTemp = global.window
8987
delete global.window
9088

9189
// "Server" side render...
@@ -95,17 +93,17 @@ describe('integration tests', () => {
9593
.then(() => {
9694
const serverString = renderToStaticMarkup(serverApp)
9795
expect(serverString).toMatchSnapshot()
98-
expect(serverContext.getState()).toMatchSnapshot()
96+
const stateForClient = serverContext.getState()
97+
expect(stateForClient).toMatchSnapshot()
9998
// Restore the window and attach the state to the "window" for the
10099
// client
101100
global.window = windowTemp
102-
global.window[STATE_IDENTIFIER] = serverContext.getState()
103-
return serverString
101+
return { serverHTML: serverString, stateForClient }
104102
})
105-
.then((serverHTML) => {
103+
.then(({ serverHTML, stateForClient }) => {
106104
// "Client" side render...
107105
const clientContext = createContext()
108-
const clientApp = createApp(clientContext)
106+
const clientApp = createApp(clientContext, stateForClient)
109107
return (
110108
asyncBootstrapper(clientApp)
111109
.then(() => {

src/constants.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/createAsyncComponent.js

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import React from 'react'
22

3-
import { STATE_IDENTIFIER } from './constants'
4-
53
const validSSRModes = ['render', 'defer', 'boundary']
64

75
function createAsyncComponent(args) {
@@ -72,29 +70,34 @@ function createAsyncComponent(args) {
7270
}
7371
}
7472

73+
// @see react-async-bootstrapper
7574
asyncBootstrapperTarget() {
7675
const { asyncComponents } = this.context
77-
const { registerError } = asyncComponents
76+
const {
77+
registerError,
78+
getRehydrate,
79+
} = asyncComponents
80+
81+
const doResolve = () =>
82+
this.resolveComponent().then(
83+
Component => typeof Component === 'function',
84+
)
7885

7986
if (typeof window !== 'undefined') {
80-
// Browser based logic
81-
if (window[STATE_IDENTIFIER]) {
82-
if (window[STATE_IDENTIFIER].errors[id]) {
83-
registerError(id, window[STATE_IDENTIFIER].errors[id])
84-
} else if (window[STATE_IDENTIFIER].resolved[id]) {
85-
return this.resolveComponent().then((Component) => {
86-
if (typeof Component === 'function') {
87-
delete window[STATE_IDENTIFIER].resolved[id]
88-
return true
89-
}
90-
return false
91-
})
92-
}
87+
// BROWSER BASED LOGIC
88+
89+
const { type, error } = getRehydrate(id)
90+
if (type === 'unresolved') {
91+
return false
9392
}
94-
return false
93+
if (type === 'error') {
94+
registerError(id, error)
95+
return false
96+
}
97+
return doResolve()
9598
}
9699

97-
// Node based logic
100+
// NODE BASED LOGIC
98101

99102
const { asyncComponentsAncestor } = this.context
100103
const isChildOfBoundary = asyncComponentsAncestor &&
@@ -104,9 +107,7 @@ function createAsyncComponent(args) {
104107
return false
105108
}
106109

107-
return this.resolveComponent().then(
108-
Component => typeof Component === 'function',
109-
)
110+
return doResolve()
110111
}
111112

112113
resolveComponent() {

src/createContext.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default function createExecContext() {
1+
export default function createContext() {
22
let idPointer = 0
33
const registry = {}
44
const errorRegistry = {}

src/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ import asyncBootstrapper from 'react-async-bootstrapper'
22
import AsyncComponentProvider from './AsyncComponentProvider'
33
import createContext from './createContext'
44
import createAsyncComponent from './createAsyncComponent'
5-
import { STATE_IDENTIFIER } from './constants'
65

76
export {
87
AsyncComponentProvider,
98
createContext,
109
createAsyncComponent,
11-
STATE_IDENTIFIER,
1210
asyncBootstrapper,
1311
}

src/types.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

src/utils.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/withAsyncComponents.js

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)