Die praktischste Lösung besteht darin, eine Bibliothek für diese Art der Reaktionsmessung zu verwenden .
Update : Es gibt jetzt einen benutzerdefinierten Hook für die Größenänderungserkennung (den ich nicht persönlich ausprobiert habe): React-Resize-Aware . Als benutzerdefinierter Haken sieht es bequemer aus als 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>
)
Um Größenänderungen zwischen Komponenten zu kommunizieren, können Sie einen onResize
Rückruf übergeben und die empfangenen Werte irgendwo speichern (die Standardmethode für den Freigabestatus ist heutzutage die Verwendung von 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>
)
}
So rollen Sie Ihre eigenen, wenn Sie es wirklich vorziehen:
Erstellen Sie eine Wrapper-Komponente, die das Abrufen von Werten aus dem DOM und das Abhören von Ereignissen zur Größenänderung von Fenstern (oder zur Erkennung der Größenänderung von Komponenten, wie sie von verwendet werden react-measure
) behandelt. Sie teilen ihm mit, welche Requisiten aus dem DOM abgerufen werden sollen, und stellen eine Renderfunktion bereit, die diese Requisiten als Kind übernimmt.
Was Sie rendern, muss gemountet werden, bevor die DOM-Requisiten gelesen werden können. Wenn diese Requisiten beim ersten Rendern nicht verfügbar sind, möchten Sie sie möglicherweise verwenden, style={{visibility: 'hidden'}}
damit der Benutzer sie nicht sehen kann, bevor er ein JS-berechnetes Layout erhält.
// @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)}/>;
}
}
Damit ist es sehr einfach, auf Breitenänderungen zu reagieren:
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>
);
shouldComponentUpdate
der beste Ort ist, um SVG zu rendern? Es klingt wie das, was Sie wollencomponentWillReceiveProps
odercomponentWillUpdate
wenn nichtrender
.