From f3c0439964178c9e5d381d6599a38af828c81904 Mon Sep 17 00:00:00 2001 From: Lionel Tzatzkin Date: Tue, 26 Mar 2019 22:29:07 +0100 Subject: [PATCH] Fix bug updating hooks and add debounced update for resize events --- .babelrc | 5 +++- package.json | 1 + src/TourHooks.js | 65 ++++++++++++++++++++++++++++++++++++------------ src/demo/App.js | 36 ++++++++++++++++----------- yarn.lock | 7 ++++++ 5 files changed, 82 insertions(+), 32 deletions(-) diff --git a/.babelrc b/.babelrc index a3d157c4..1b596e77 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,7 @@ { "presets": ["@babel/env", "@babel/react"], - "plugins": ["@babel/plugin-proposal-class-properties"] + "plugins": [ + "@babel/plugin-proposal-class-properties", + "@babel/plugin-syntax-dynamic-import" + ] } diff --git a/package.json b/package.json index 0e3ef10c..4bfb2ea1 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@babel/cli": "7.2.3", "@babel/core": "7.4.0", "@babel/plugin-proposal-class-properties": "7.4.0", + "@babel/plugin-syntax-dynamic-import": "7.2.0", "@babel/polyfill": "7.4.0", "@babel/preset-env": "7.4.2", "@babel/preset-react": "7.0.0", diff --git a/src/TourHooks.js b/src/TourHooks.js index dec85db9..b612851e 100644 --- a/src/TourHooks.js +++ b/src/TourHooks.js @@ -1,8 +1,8 @@ -import React, { useState, useReducer, useEffect, createRef } from 'react' +import React, { useState, useReducer, useEffect, useRef, memo } from 'react' import cn from 'classnames' import scrollSmooth from 'scroll-smooth' import Scrollparent from 'scrollparent' - +import debounce from 'lodash.debounce' import Portal from './Portal' import { SvgMask, @@ -22,11 +22,9 @@ function Tour({ isOpen, startAt, steps, - scrollDuration, inViewThreshold, scrollOffset, - disableInteraction, disableKeyboardNavigation, className, @@ -48,20 +46,24 @@ function Tour({ }) { const [current, setCurrent] = useState(0) const [state, dispatch] = useReducer(reducer, initialState) - const helper = createRef() + const helper = useRef(null) useEffect(() => { + const debouncedShowStep = debounce(showStep, 100) window.addEventListener('keydown', keyHandler, false) + window.addEventListener('resize', debouncedShowStep, false) return () => { window.removeEventListener('keydown', keyHandler) + window.removeEventListener('resize', debouncedShowStep) } }, []) + useWhyDidYouUpdate('Counter', { current, state, isOpen }) useEffect(() => { if (isOpen) { open(startAt) - showStep() + if (helper.current) { helper.current.focus() } @@ -70,7 +72,7 @@ function Tour({ useEffect(() => { if (isOpen) showStep() - }, [current]) + }, [isOpen, current]) function keyHandler(e) { e.stopPropagation() @@ -107,7 +109,7 @@ function Tour({ } function open(startAt) { - const firstStep = startAt || 0 + const firstStep = startAt || current setCurrent(firstStep) if (onAfterOpen) { @@ -130,9 +132,9 @@ function Tour({ function showStep() { const step = steps[current] const node = step.selector ? document.querySelector(step.selector) : null + const { w, h } = getWindow() if (node) { // DOM node exists - const { w, h } = getWindow() const nodeRect = hx.getNodeRect(node) // step is outside view @@ -153,9 +155,6 @@ function Tour({ // No DOM node dispatch({ type: 'without_node', - // ...nodeRect, - helperWidth, - helperHeight, helperPosition: step.position, w, h, @@ -349,11 +348,11 @@ function reducer(state, action) { top: state.h + 10, right: state.w / 2 + 9, bottom: state.h / 2 + 9, - left: w / 2 - state.helperWidth / 2, + left: action.w / 2 - state.helperWidth / 2, width: 0, height: 0, - w, - h, + w: action.w, + h: action.h, helperPosition: 'center', } default: @@ -365,4 +364,38 @@ Tour.propTypes = propTypes Tour.defaultProps = defaultProps -export default Tour +function useWhyDidYouUpdate(name, props) { + // Get a mutable ref object where we can store props ... + // ... for comparison next time this hook runs. + const previousProps = useRef() + + useEffect(() => { + if (previousProps.current) { + // Get all keys from previous and current props + const allKeys = Object.keys({ ...previousProps.current, ...props }) + // Use this object to keep track of changed props + const changesObj = {} + // Iterate through keys + allKeys.forEach(key => { + // If previous is different from current + if (previousProps.current[key] !== props[key]) { + // Add to changesObj + changesObj[key] = { + from: previousProps.current[key], + to: props[key], + } + } + }) + + // If changesObj not empty then output to console + if (Object.keys(changesObj).length) { + console.log('[why-did-you-update]', name, changesObj) + } + } + + // Finally update previousProps with current props for next hook call + previousProps.current = props + }) +} + +export default memo(Tour) diff --git a/src/demo/App.js b/src/demo/App.js index e6494230..8c8cff29 100644 --- a/src/demo/App.js +++ b/src/demo/App.js @@ -1,6 +1,6 @@ -import React, { Component, useState, useEffect } from 'react' +import React, { Component, useState, useEffect, Suspense, lazy } from 'react' import Demo from './Demo' -import Tour, { Arrow } from '../index' +import { Arrow } from '../index' import Text from './Text' import Glitch from './Glitch' import Tooltip from './Tooltip' @@ -10,6 +10,10 @@ import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock' import './styles.css' +const LazyTour = React.lazy(() => + import(/* webpackChunkName: "reactour" */ '../index') +) + function App() { const [isTourOpen, setOpen] = useState(false) const [isShowingMore, setShowingMore] = useState(false) @@ -41,18 +45,20 @@ function App() { toggleShowMore={() => setShowingMore(!isShowingMore)} isShowingMore={isShowingMore} /> - setOpen(false)} - steps={tourConfig} - isOpen={isTourOpen} - maskClassName="mask" - className="helper" - rounded={5} - accentColor={accentColor} - CustomHelper={customComps ? MyCustomHelper : null} - /> + }> + setOpen(false)} + steps={tourConfig} + isOpen={isTourOpen} + maskClassName="mask" + className="helper" + rounded={5} + accentColor={accentColor} + CustomHelper={customComps ? MyCustomHelper : null} + /> + ) } @@ -116,7 +122,7 @@ const tourConfig = [ "Ok, let's start with the name of the Tour that is about to begin.", }, { - selector: '[data-tut="reactour__logo"]', + selector: '[data-tut="reactour__logoooo"]', content: 'And this is our cool bus...', }, { diff --git a/yarn.lock b/yarn.lock index f13c0ad1..85e346b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -345,6 +345,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-dynamic-import@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" + integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470"