2016-11-14 65 views
2

我想根據瀏覽器窗口的當前大小來設置組件的狀態。服務器端渲染已被使用(React + Redux)。我正考慮使用Redux商店作爲膠水 - 只是爲了更新商店的大小。 有沒有其他/更好的解決方案,不涉及Redux。 謝謝。React同構渲染 - 處理窗口大小調整事件

class FocalImage extends Component { 

    // won't work - the backend rendering is used 
    // componentDidMount() { 
    // window.addEventListener(...); 
    //} 

    //componentWillUnmount() { 
    // window.removeEventListener('resize' ....); 
    //} 

    onresize(e) { 
    // 
    } 

    render() { 
    const {src, className, nativeWidth, nativeHeight} = this.props; 
    return (
     <div className={cn(className, s.focalImage)}> 
     <div className={s.imageWrapper}> 
      <img src={src} className={_compare_ratios_ ? s.tall : s.wide}/> 
     </div> 
     </div> 
    ); 
    } 
} 
+0

'componentDidMount'不叫服務器端渲染。 – xiaofan2406

回答

4

我有一個調整大小的輔助組件,我可以通過一個函數,它看起來像這樣:

class ResizeHelper extends React.Component { 

    static propTypes = { 
     onWindowResize: PropTypes.func, 
    }; 

    constructor() { 
     super(); 
     this.handleResize = this.handleResize.bind(this); 
    } 

    componentDidMount() { 
     if (this.props.onWindowResize) { 
      window.addEventListener('resize', this.handleResize); 
     } 
    } 

    componentWillUnmount() { 
     if (this.props.onWindowResize) { 
      window.removeEventListener('resize', this.handleResize); 
     } 
    } 

    handleResize(event) { 
     if ('function' === typeof this.props.onWindowResize) { 
      // we want this to fire immediately the first time but wait to fire again 
      // that way when you hit a break it happens fast and only lags if you hit another break immediately 
      if (!this.resizeTimer) { 
       this.props.onWindowResize(event); 
       this.resizeTimer = setTimeout(() => { 
        this.resizeTimer = false; 
       }, 250); // this debounce rate could be passed as a prop 
      } 
     } 
    } 

    render() { 
     return (<div />); 
    } 
} 

然後需要做調整大小的東西任何組件都可以使用它像這樣:

<ResizeHelper onWindowResize={this.handleResize} /> 

您還可能需要在componentDidMount上調用一次傳遞的函數來設置UI。由於componentDidMount和componentWillUnmount永遠不會在服務器上調用,所以在我的同構App中完美工作。

2

我的解決辦法是處理上最頂層調整事件,它向下傳遞到我的最上面的部分,你可以看到完整的代碼here,但要點是:

let prevBrowserWidth 
 

 
//re-renders only if container size changed, good place to debounce 
 
let renderApp = function() { 
 
    const browserWidth = window.document.body.offsetWidth 
 

 
    //saves re-render if nothing changed 
 
    if (browserWidth === prevBrowserWidth) { 
 
    return 
 
    } 
 

 
    prevBrowserWidth = browserWidth 
 

 
    render(<App browserWidth={browserWidth} />, document.getElementById('root')) 
 
} 
 

 
//subscribing to resize event 
 
window.addEventListener('resize', renderApp)

它顯然沒有Redux的工作(雖然我仍然使用Redux),我認爲這將很容易做到與Redux相同。與使用組件的方案相比,此解決方案的優勢在於,您的反應組件完全不受此影響,並與瀏覽器寬度一起工作,與傳遞其他任何道具一樣。所以這是一個本地化的地方來處理副作用。缺點是它只給你一個屬性而不是事件本身,所以你不能真正依靠它來觸發渲染函數之外的東西。


除此之外,你可以變通方法,您的服務器端通過使用類似渲染問題:

import ExecutionEnvironment from 'exenv' 
 

 
    //... 
 
    
 
componentWillMount() { 
 
    if (ExecutionEnvironment.canUseDOM) { 
 
     window.addEventListener(...); 
 
    } 
 
    }

+0

謝謝你的解決方案。接受本的解決方案,以提高他的聲譽(遠低於你的),因爲這兩種解決方案都是有效的。 – DraganS