Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.12.7 #1300

Merged
merged 2 commits into from Jul 16, 2019
Merged

4.12.7 #1300

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .prettierignore
Expand Up @@ -9,4 +9,5 @@ babel.js
index.js
patch.js
root.js
test/hot/react-dom
test/hot/react-dom
coverage
5 changes: 5 additions & 0 deletions README.md
Expand Up @@ -67,6 +67,11 @@ There is only one condition for it - a non zero dependencies list.
🔥 useEffect(effect, ["hot"]); // the simplest way to make hook reloadable
```

**Plus**

* any hook would be reloaded on a function body change. Enabled by default, controlled by `reloadHooksOnBodyChange` option.
* you may configure RHL to reload any hook by setting `reloadLifeCycleHooks` option to true.

**To disable hooks reloading** - set configuration option:

```js
Expand Down
8 changes: 7 additions & 1 deletion src/configuration.js
Expand Up @@ -11,9 +11,15 @@ const configuration = {
// Allows SFC to be used, enables "intermediate" components used by Relay, should be disabled for Preact
allowSFC: true,

// Allow hot reload of effect hooks
// Allow reload of effect hooks with non zero dependency list
reloadHooks: true,

// Allow reload of mount effect hooks - zero deps
reloadLifeCycleHooks: false,

// Enables hook reload on hook body change
reloadHooksOnBodyChange: true,

// Disable "hot-replacement-render"
disableHotRenderer: false,

Expand Down
20 changes: 18 additions & 2 deletions src/reactHotLoader.js
Expand Up @@ -29,8 +29,24 @@ const forceSimpleSFC = { proxy: { pureSFC: true } };

const hookWrapper = hook => {
const wrappedHook = function(cb, deps) {
if (configuration.reloadHooks) {
return hook(cb, deps && deps.length > 0 ? [...deps, getHotGeneration()] : deps);
if (configuration.reloadHooks && deps) {
const inputs = [...deps];

// reload hooks which have changed string representation
if (configuration.reloadHooksOnBodyChange) {
inputs.push(String(cb));
}

if (
// reload hooks with dependencies
deps.length > 0 ||
// reload all hooks of option is set
(configuration.reloadLifeCycleHooks && deps.length === 0)
) {
inputs.push(getHotGeneration());
}

return hook(cb, inputs);
}
return hook(cb, deps);
};
Expand Down
50 changes: 27 additions & 23 deletions src/reconciler/componentComparator.js
Expand Up @@ -182,41 +182,45 @@ const compareComponents = (oldType, newType, setNewType, baseType) => {
const knownPairs = new WeakMap();
const emptyMap = new WeakMap();

const getKnownPair = (oldType, newType) => {
const pair = knownPairs.get(oldType) || emptyMap;
return pair.get(newType);
};

export const hotComponentCompare = (oldType, preNewType, setNewType, baseType) => {
const hotActive = hotComparisonOpen();
const newType = configuration.integratedResolver ? resolveType(preNewType) : preNewType;
let result = oldType === newType;

if (!hotActive) {
return result;
}
// TODO: find out the root cause
// we could not use "fast result" here - go a full part to update a fiber.
// const knownType = getKnownPair(oldType, newType);
// if (knownType !== undefined) {
// return knownType;
// }

if (
!isReloadableComponent(oldType) ||
!isReloadableComponent(newType) ||
isColdType(oldType) ||
isColdType(oldType) ||
!oldType ||
!newType ||
0
) {
return result;
}
let result = oldType === newType;

// comparison should be active only if hot update window
// or it would merge components it shall not
if (hotActive) {
// pre fail components which could not be merged
if (
!isReloadableComponent(oldType) ||
!isReloadableComponent(newType) ||
isColdType(oldType) ||
isColdType(oldType) ||
!oldType ||
!newType ||
0
) {
return result;
}

result = compareComponents(oldType, newType, setNewType, baseType);
const pair = knownPairs.get(oldType) || new WeakMap();
pair.set(newType, result);
knownPairs.set(oldType, pair);
return result;
}

if (result) {
return result;
}

const pair = knownPairs.get(oldType) || emptyMap;
return pair.get(newType) || false;
// result - true if components are equal, or were "equal" at any point in the past
return result || getKnownPair(oldType, newType) || false;
};
16 changes: 11 additions & 5 deletions src/reconciler/resolver.js
Expand Up @@ -12,17 +12,23 @@ import configuration, { internalConfiguration } from '../configuration';
const shouldNotPatchComponent = type => isTypeBlacklisted(type);

export function resolveType(type, options = {}) {
const element = { type };
if (isLazyType(element) || isMemoType(element) || isForwardType(element) || isContextType(element)) {
return getProxyByType(type) || type;
}

// fast return
if (!isCompositeComponent(type) || isProxyType(type)) {
return type;
}

const element = { type };

// fast meta
if (typeof element === 'object') {
if (isLazyType(element) || isMemoType(element) || isForwardType(element) || isContextType(element)) {
return getProxyByType(type) || type;
}
}

const existingProxy = getProxyByType(type);

// cold API
if (shouldNotPatchComponent(type)) {
return existingProxy ? existingProxy.getCurrent() : type;
}
Expand Down