diff --git a/lib/link.js b/lib/link.js
index 2e8132bd..d9897847 100644
--- a/lib/link.js
+++ b/lib/link.js
@@ -2,7 +2,6 @@
import { resolve, format, parse } from 'url'
import React, { Component, Children } from 'react'
-import {polyfill} from 'react-lifecycles-compat'
import PropTypes from 'prop-types'
import exact from 'prop-types-exact'
import Router, { _rewriteUrlForNextExport } from './router'
@@ -18,6 +17,23 @@ function isLocal (href) {
const warnLink = execOnce(warn)
+function memoizedFormatUrl (formatUrl) {
+ let lastHref = null
+ let lastAs = null
+ let lastResult = null
+ return (href, as) => {
+ if (href === lastHref && as === lastAs) {
+ return lastResult
+ }
+
+ const result = formatUrl(href, as)
+ lastHref = href
+ lastAs = as
+ lastResult = result
+ return result
+ }
+}
+
class Link extends Component {
static propTypes = exact({
href: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
@@ -41,11 +57,6 @@ class Link extends Component {
]).isRequired
})
- constructor (props, ...rest) {
- super(props, ...rest)
- this.formatUrls(props)
- }
-
componentDidMount () {
this.prefetch()
}
@@ -56,21 +67,18 @@ class Link extends Component {
}
}
- // eslint-disable-next-line camelcase
- UNSAFE_componentWillReceiveProps (nextProps) {
- this.formatUrls(nextProps)
- }
-
- // We accept both 'href' and 'as' as objects which we can pass to `url.format`.
- // We'll handle it here.
- formatUrls (props) {
- this.href = props.href && typeof props.href === 'object'
- ? format(props.href)
- : props.href
- this.as = props.as && typeof props.as === 'object'
- ? format(props.as)
- : props.as
- }
+ // The function is memoized so that no extra lifecycles are needed
+ // as per https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
+ formatUrls = memoizedFormatUrl((href, asHref) => {
+ return {
+ href: href && typeof href === 'object'
+ ? format(href)
+ : href,
+ as: asHref && typeof asHref === 'object'
+ ? format(asHref)
+ : asHref
+ }
+ })
linkClicked = e => {
const { nodeName, target } = e.currentTarget
@@ -80,8 +88,7 @@ class Link extends Component {
return
}
- const { shallow } = this.props
- let { href, as } = this
+ let { href, as } = this.formatUrls(this.props.href, this.props.as)
if (!isLocal(href)) {
// ignore click if it's outside our scope
@@ -105,7 +112,7 @@ class Link extends Component {
const changeMethod = replace ? 'replace' : 'push'
// straight up redirect
- Router[changeMethod](href, as, { shallow })
+ Router[changeMethod](href, as, { shallow: this.props.shallow })
.then((success) => {
if (!success) return
if (scroll) {
@@ -124,13 +131,14 @@ class Link extends Component {
// Prefetch the JSON page if asked (only in the client)
const { pathname } = window.location
- const href = resolve(pathname, this.href)
+ const {href: parsedHref} = this.formatUrls(this.props.href, this.props.as)
+ const href = resolve(pathname, parsedHref)
Router.prefetch(href)
}
render () {
let { children } = this.props
- let { href, as } = this
+ let { href, as } = this.formatUrls(this.props.href, this.props.as)
// Deprecated. Warning shown by propType check. If the childen provided is a string (example) we wrap it in an tag
if (typeof children === 'string') {
children = {children}
@@ -169,6 +177,4 @@ class Link extends Component {
}
}
-// Make UNSAFE_ compatible with version of React under 16.3
-polyfill(Link)
export default Link