如何在React中响应自动调整大小的DOM元素的宽度?

我有一个使用React组件的复杂网页,并且正在尝试将该页面从静态布局转换为响应更快,可调整大小的布局。但是,我一直遇到React的限制,并且想知道是否存在用于处理这些问题的标准模式。在我的特定情况下,我有一个使用display:table-

cell和width:auto呈现为div的组件。

不幸的是,我无法查询组件的宽度,因为您无法计算元素的大小,除非将其实际放置在DOM中(该元素具有推论实际渲染宽度的完整上下文)。除了用于相对鼠标定位之类的功能外,我还需要此功能来在组件内的SVG元素上正确设置宽度属性。

另外,当窗口调整大小时,如何在安装过程中将尺寸变化从一个组件传递到另一个组件?我们正在shouldComponentUpdate中完成所有第三方SVG渲染,但是您无法在该方法中设置自己或其他子组件的状态或属性。

是否有使用React处理此问题的标准方法?

回答:

最实用的解决方案是使用库来进行类似react-measure的操作。

:现在有一个用于调整大小检测的自定义钩子(我没有亲自尝试过):react-resize-

aware。作为自定义挂钩,它看起来比起来更方便react-measure

import * as React from 'react'

import Measure from 'react-measure'

const MeasuredComp = () => (

<Measure bounds>

{({ measureRef, contentRect: { bounds: { width }} }) => (

<div ref={measureRef}>My width is {width}</div>

)}

</Measure>

)

为了传达组件之间的大小变化,您可以传递一个onResize回调并将接收到的值存储在某个地方(如今,共享状态的标准方法是使用Redux):

import * as React from 'react'

import Measure from 'react-measure'

import { useSelector, useDispatch } from 'react-redux'

import { setMyCompWidth } from './actions' // some action that stores width in somewhere in redux state

export default function MyComp(props) {

const width = useSelector(state => state.myCompWidth)

const dispatch = useDispatch()

const handleResize = React.useCallback(

(({ contentRect })) => dispatch(setMyCompWidth(contentRect.bounds.width)),

[dispatch]

)

return (

<Measure bounds onResize={handleResize}>

{({ measureRef }) => (

<div ref={measureRef}>MyComp width is {width}</div>

)}

</Measure>

)

}

创建一个包装器组件,该组件处理从DOM获取值并监听窗口调整大小事件(或所使用的组件调整大小检测react-

measure)。您告诉它要从DOM获取哪些道具,并提供将这些道具作为子对象的渲染函数。

必须先安装渲染的内容,然后才能读取DOM属性;当这些道具在初始渲染期间不可用时,您可能需要使用它,style={{visibility:

'hidden'}}以便用户在获得JS计算的布局之前看不到它。

// @flow

import React, {Component} from 'react';

import shallowEqual from 'shallowequal';

import throttle from 'lodash.throttle';

type DefaultProps = {

component: ReactClass<any>,

};

type Props = {

domProps?: Array<string>,

computedStyleProps?: Array<string>,

children: (state: State) => ?React.Element<any>,

component: ReactClass<any>,

};

type State = {

remeasure: () => void,

computedStyle?: Object,

[domProp: string]: any,

};

export default class Responsive extends Component<DefaultProps,Props,State> {

static defaultProps = {

component: 'div',

};

remeasure: () => void = throttle(() => {

const {root} = this;

if (!root) return;

const {domProps, computedStyleProps} = this.props;

const nextState: $Shape<State> = {};

if (domProps) domProps.forEach(prop => nextState[prop] = root[prop]);

if (computedStyleProps) {

nextState.computedStyle = {};

const computedStyle = getComputedStyle(root);

computedStyleProps.forEach(prop =>

nextState.computedStyle[prop] = computedStyle[prop]

);

}

this.setState(nextState);

}, 500);

// put remeasure in state just so that it gets passed to child

// function along with computedStyle and domProps

state: State = {remeasure: this.remeasure};

root: ?Object;

componentDidMount() {

this.remeasure();

this.remeasure.flush();

window.addEventListener('resize', this.remeasure);

}

componentWillReceiveProps(nextProps: Props) {

if (!shallowEqual(this.props.domProps, nextProps.domProps) ||

!shallowEqual(this.props.computedStyleProps, nextProps.computedStyleProps)) {

this.remeasure();

}

}

componentWillUnmount() {

this.remeasure.cancel();

window.removeEventListener('resize', this.remeasure);

}

render(): ?React.Element<any> {

const {props: {children, component: Comp}, state} = this;

return <Comp ref={c => this.root = c} children={children(state)}/>;

}

}

这样,响应宽度变化非常简单:

function renderColumns(numColumns: number): React.Element<any> {

...

}

const responsiveView = (

<Responsive domProps={['offsetWidth']}>

{({offsetWidth}: {offsetWidth: number}): ?React.Element<any> => {

if (!offsetWidth) return null;

const numColumns = Math.max(1, Math.floor(offsetWidth / 200));

return renderColumns(numColumns);

}}

</Responsive>

);

以上是 如何在React中响应自动调整大小的DOM元素的宽度? 的全部内容, 来源链接: utcz.com/qa/434896.html

回到顶部