2017-12-07 15 views
0

ページナビゲーションのためにスクロールハンドラでNext.js命令型ルーティングAPIを使用しようとしています。ウィンドウにアタッチすると、スクロール位置がリセットされるときに色が「フラッシュ」するという小さな例外があります(前のページの上を移動すると新しいルートの下からスクロールし続ける必要があります。色の遷移はシームレスである必要があります。これは、ブラウザのミリ秒単位でscrollTopが0になっているために不可能と思われます)。コード:Next.jsで奇妙な必須のonScrollルーティング動作(サーバ上のレンダリングのみ)

export default class ScrollOMatic extends Component { 
 
    constructor(props) { 
 
    super(props) 
 
    this.state = { 
 
     prevRoute: '', 
 
     nextRoute: '', 
 
     isEndOfScroll: false 
 
    } 
 
    binder(this, ['handleScroll']) 
 
    } 
 
    componentWillMount() { 
 
    if (typeof window !== 'undefined') { 
 
     console.log(window) 
 
    } 
 
    } 
 
    componentDidMount() { 
 
    window.addEventListener('scroll', this.handleScroll) 
 
    const { 
 
     prevRoute, 
 
     nextRoute 
 
    } = this.props.routeData 
 
    this.setState({ 
 
     prevRoute, 
 
     nextRoute 
 
    }) 
 
    Router.prefetch('us') 
 
    Router.prefetch('work') 
 
    Router.prefetch('services') 
 
    Router.prefetch('converse') 
 
    } 
 
    componentWillUnmount() { 
 
    window.removeEventListener('scroll', this.handleScroll) 
 
    } 
 
    handleScroll(e) { 
 
    e.preventDefault() 
 
    let { 
 
     scrollTop, 
 
     scrollHeight 
 
    } = e.srcElement.scrollingElement 
 
    scrollHeight = scrollHeight/2 
 
    const scrollTiplier = scrollTop/scrollHeight 
 
    if (scrollTop === 0) { 
 
     Router.push(this.state.prevRoute) 
 
     window.scrollTo(0, scrollHeight - 1, { 
 
     duration: 0 
 
     }) 
 
    } 
 
    if (scrollTiplier === 1) { 
 
     Router.push(this.state.nextRoute) 
 
     window.scrollTo(0, 1, { 
 
     duration: 0 
 
     }) 
 
    } 
 
    } 
 
    render() { 
 
    return ( 
 
     <div className = 'scroll-o-matic' >{ this.props.children }</div> 
 
    ) 
 
    } 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

だから、私は有望と思われる反応-水平スクロールに触発され、独自のスクロール動作、とコンテナを使用しています。しかし、この新しいコードでは奇妙なことが起こります。新しいルートはクライアント側にレンダリングされ、サーバーから新しいルートがフェッチされるとページがリフレッシュされます。 GIFおよびコードを参照してください: enter image description here

// inspired by react-horizontal-scroll 
 
import { Motion, spring, presets } from 'react-motion' 
 
import raf from 'raf' 
 
import Router from 'next/router' 
 
import { fadeColor, binder } from '../../lib/_utils' 
 
import { setScrollState } from '../../lib/_navRules' 
 

 
export default class ScrollOMatic extends Component { 
 
    constructor (props) { 
 
    super(props) 
 
    this.state = { 
 
     prevRoute: '', 
 
     nextRoute: '', 
 
     animValues: 0 
 
    } 
 
    binder(this, ['handleWheel', 'resetMin', 'resetMax', 'navigator', 'canIscroll', 'getLayoutData']) 
 
    } 
 
    componentDidMount() { 
 
    const { prevRoute, nextRoute } = this.props.routeData 
 
    this.setState({ 
 
     prevRoute, 
 
     nextRoute 
 
    }) 
 

 
    const prevRouteName = prevRoute === '/' ? 'index' : prevRoute.replace('/', '') 
 
    const nextRouteName = prevRoute === '/' ? 'index' : nextRoute.replace('/', '') 
 
    Router.prefetch(prevRouteName) 
 
    Router.prefetch(nextRouteName) 
 
    } 
 

 
    componentWillReceiveProps (nextProps) { 
 
    if (this.props.children !== nextProps.children) { this.resetMin() } 
 
    } 
 

 
    shouldComponentUpdate (nextProps, nextState) { 
 
    if (true && 
 
     this.calculate.timer !== void 0 && 
 
     this.props.children === nextProps.children && 
 
     this.state.animValues === nextState.animValues) { 
 
     return false 
 
    } 
 
    if (true && 
 
     this.props.children === nextProps.children && 
 
     this.canIscroll() === false) { 
 
     return false 
 
    } 
 
    return true 
 
    } 
 

 
    componentDidUpdate() { this.calculate() } 
 

 
    getLayoutData() { 
 
    const scrollOMatic = DOM.findDOMNode(this.scrollOMatic) 
 
    const scrollTray = DOM.findDOMNode(this.scrollTray) 
 
    const max = scrollOMatic.scrollHeight 
 
    const win = scrollOMatic.offsetHeight 
 
    const currentVal = this.state.animValues 
 
    const bounds = -(max - win) 
 
    const trayTop = scrollTray.offsetTop 
 
    const trayOffsetHeight = scrollTray.offsetHeight 
 
    const trayScrollHeight = scrollTray.scrollHeight 
 
    const scrollOMaticRect = scrollOMatic.getBoundingClientRect() 
 
    const scrollOMaticTop = scrollOMaticRect.top 
 
    const scrollOMaticHeight = scrollOMaticRect.height 
 
    const scrollOMaticOffsetHeight = scrollOMatic.offsetHeight 
 
    return { 
 
     currentVal, 
 
     bounds, 
 
     scrollTray, 
 
     trayTop, 
 
     trayOffsetHeight, 
 
     trayScrollHeight, 
 
     scrollOMatic, 
 
     scrollOMaticTop, 
 
     scrollOMaticHeight, 
 
     scrollOMaticOffsetHeight, 
 
     scrollOMaticRect 
 
    } 
 
    } 
 

 
    calculate() { 
 
    const layout = this.getLayoutData() 
 
    clearTimeout(this.calculate.timer) 
 
    this.calculate.timer = setTimeout(() => { 
 
     const max = layout.trayScrollHeight 
 
     const win = layout.scrollOMaticOffsetHeight 
 
     const currentVal = this.state.animValues 
 
     const bounds = -(max - win) 
 
     if (currentVal >= 1) { 
 
     this.resetMin() 
 
     } else if (currentVal <= bounds) { 
 
     const x = bounds + 1 
 
     this.resetMax(x) 
 
     } 
 
    }) 
 
    } 
 

 
    resetMin() { this.setState({ animValues: 0 }) } 
 
    resetMax (x) { this.setState({ animValues: x }) } 
 

 
    canIscroll() { 
 
    const layout = this.getLayoutData() 
 
    return layout.trayOffsetTop < layout.scrollOMaticTop || 
 
     layout.trayOffsetHeight > layout.scrollOMaticHeight 
 
    } 
 

 
    handleWheel (e) { 
 
    e.preventDefault() 
 
    const rawData = e.deltaY ? e.deltaY : e.deltaX 
 
    const mouseY = Math.floor(rawData) 
 
    const animationVal = this.state.animValues 
 
    const newAnimationVal = (animationVal + mouseY) 
 
    const newAnimationValNeg = (animationVal - mouseY) 
 

 
    if (!this.canIscroll()) return 
 

 
    const layout = this.getLayoutData() 
 
    const { currentVal, scrollOMaticHeight, trayScrollHeight } = layout 
 
    const isEndOfPage = -(currentVal - scrollOMaticHeight) + 1 === trayScrollHeight 
 

 
    this.navigator() 
 

 
    const scrolling =() => { 
 
     this.state.scrollInverted 
 
     ? this.setState({ animValues: newAnimationValNeg }) 
 
     : this.setState({ animValues: newAnimationVal }) 
 
    } 
 
    raf(scrolling) 
 
    } 
 
    
 
    navigator() { 
 
    const layout = this.getLayoutData() 
 
    const { currentVal, scrollOMaticHeight, trayScrollHeight } = layout 
 
    const shouldBeNextRoute = -(currentVal - scrollOMaticHeight) + 1 >= trayScrollHeight 
 
    // const shouldBePrevRoute = this.state.animValues < 0 
 

 
    if (shouldBeNextRoute) { 
 
     Router.push(this.state.nextRoute) 
 
    } 
 
    // if (shouldBePrevRoute) { 
 
    // Router.push(this.state.prevRoute)  
 
    // } 
 
    } 
 

 
    render() { 
 
    const springConfig = presets.noWobble 
 
    return (
 
     <div style={{ position: 'relative', width: '100vw', height: '100vh' }} className='scroll-o-matic' onWheel={this.handleWheel} 
 
     ref={scrollOMatic => { this.scrollOMatic = scrollOMatic }}> 
 
     <Motion style={{ z: spring(this.state.animValues, springConfig) }}> 
 
      { ({ z }) => (
 
      <div className='scroll-tray' ref={(scrollTray) => { this.scrollTray = scrollTray }} 
 
       style={{ 
 
       height: '300vh', 
 
       width: '100vw', 
 
       // top: '-100vh', 
 
       transform: `translate3d(0,${z.toFixed(3)}px,0)`, 
 
       willChange: 'transform', 
 
       display: 'inline-flex', 
 
       position: 'absolute' 
 
       }}> 
 
       { this.props.children } 
 
      </div> 
 
     )} 
 
     </Motion> 
 
     <style jsx>{` 
 
      .scroll-o-matic { 
 
      background-color: ${this.state.currentColor}; 
 
      } 
 
     `}</style> 
 
     </div> 
 
    ) 
 
    } 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

サーバコード:

const express = require('express') 
 
const next = require('next') 
 

 
const dev = process.env.NODE_ENV !== 'production' 
 
const app = next({ dev }) 
 
const port = process.env.PORT || 3000 
 
const handle = app.getRequestHandler() 
 

 
app.prepare() 
 
    .then(() => { 
 
    const server = express() 
 
    server.use('/static', express.static('static')) 
 

 
    server.get('/', (req, res) => { 
 
     return app.render(req, res, '/', req.query) 
 
    }) 
 
    server.get('/us', (req, res) => { 
 
     return app.render(req, res, '/us', req.query) 
 
    }) 
 
    server.get('/work', (req, res) => { 
 
     return app.render(req, res, '/work', req.query) 
 
    }) 
 
    server.get('/services', (req, res) => { 
 
     return app.render(req, res, '/services', req.query) 
 
    }) 
 
    server.get('/converse', (req, res) => { 
 
     return app.render(req, res, '/converse', req.query) 
 
    }) 
 

 
    server.get('*', (req, res) => { 
 
     return handle(req, res, '/', req.query) 
 
    }) 
 

 
    server.listen(port, (err) => { 
 
     if (err) throw err 
 
     console.log(`> Ready on http://localhost:${port}`) 
 
    }) 
 
    })

たぶん私は間違いなく次の 'プリフェッチ' を理解し、それはありません先読みしていないようです。私は主になぜサーバー側のページの読み込みが起こっているのか混乱しています。エクスプレスでワイルドカードリクエストハンドラを使用しても、ページはリロードされますが、自分自身にリダイレクトされるため、私は思っていないサーバー構成には問題ありません。

インターネットの欠点は何ですか?

答えて

1

あなたはそれがすでにレンダリングをプリフェッチすることが予想される場合は、プリフェッチ・オプションは、バックグラウンドでページのJSコードをダウンロードされていないので、あなたは、ページの変更をしたいときには、既にダウンロードですが、より多くの何もHTMLやそれを手動で実装するために必要なデータ

0

同じ問題を抱えている可能性のある人にとっては、それはそのままですが、問題は次の「Styled JSX」レンダリング方法に関連しています。

クライアント側のページが読み込まれていても、何らかの理由で、Styled JSXをロードする必要がある時間が半分ほどです。アプリ全体の背景色と同じようなものがあなたの<style jsx>{``}<style>タグの内部にない限り、通常気付いていないものです。すべてのスタイルを通常の古いHTMLスタイルattrに入れて、 'flash'を解決しました。