如何在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计算的布局之前看不到它。
// @flowimport 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