2016-11-14 83 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