Add custom Redirect component

react-router v4 was made before React introduced a more performant
function renderToNodeStream to replace renderToString. All guides for
react-router are made using renderToString method, but I would love to
use the renderToNodeStream instead.

Since we cannot issue a 302 redirect after the page has already been
rendered (because status codes are written first), we can display a
<a> link with a text message. Once the React client-side library
hydrates the DOM Tree, the redirect should happen client side, so no
user action should be required.

This idea was taken from:
https://github.com/ReactTraining/react-router/issues/6191
This commit is contained in:
Jerko Steiner 2019-03-17 19:59:44 +05:00
parent 3fae7adc4a
commit cf8aefd099
3 changed files with 71 additions and 0 deletions

View File

@ -0,0 +1,48 @@
import React from 'react'
import {renderToString} from 'react-dom/server'
import T from 'react-dom/test-utils'
import {Redirect} from './Redirect'
import {LocationDescriptorObject} from 'history'
import {
MemoryRouter,
// Redirect as RouterRedirect,
Route,
} from 'react-router-dom'
function getJSX(to: LocationDescriptorObject | string = '/test1234') {
return (
<MemoryRouter initialEntries={['/two']}>
<Route path='/one' render={() => <span>Ok</span>} />
<Route path='/two' render={() => <Redirect to={to} />} />
</MemoryRouter>
)
}
describe('Redirect - client side', () => {
it('renders a redirect component', () => {
T.renderIntoDocument(getJSX())
})
})
describe('Redirect - server side', () => {
const g: any = global
const window = g.window
beforeEach(() => {
delete g.window
})
afterEach(() => {
g.window = window
})
it('renders a href component', () => {
const html = renderToString(getJSX())
expect(html).toContain('<a href="/test1234">here</a>')
})
it('handles LocationDescriptorObject', () => {
const html = renderToString(getJSX({
pathname: '/test1234',
}))
expect(html).toContain('<a href="/test1234">here</a>')
})
})

View File

@ -0,0 +1,22 @@
import React from 'react'
import {Redirect as RouterRedirect} from 'react-router-dom'
import {RedirectProps} from 'react-router'
import {isClientSide} from '../renderer'
export class Redirect extends React.PureComponent<RedirectProps> {
render() {
if (isClientSide()) {
return <RouterRedirect {...this.props}/>
}
const href = typeof this.props.to === 'string'
? this.props.to : this.props.to.pathname
return (
<span>
You are being redirected.
Click <a href={href}>here</a> to 'continue'
</span>
)
}
}

View File

@ -1,3 +1,4 @@
export * from './Button'
// export * from './Component'
export * from './Input'
export * from './Redirect'