Solusi paling praktis adalah menggunakan perpustakaan untuk pengukuran reaksi seperti ini .
Pembaruan : sekarang ada kait khusus untuk deteksi pengubahan ukuran (yang belum saya coba secara pribadi): react-resize-aware . Menjadi pengait khusus, terlihat lebih nyaman digunakan daripada 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>
)
Untuk mengomunikasikan perubahan ukuran antar komponen, Anda dapat meneruskan onResize
callback dan menyimpan nilai yang diterimanya di suatu tempat (cara standar berbagi status saat ini adalah dengan menggunakan Redux ):
import * as React from 'react'
import Measure from 'react-measure'
import { useSelector, useDispatch } from 'react-redux'
import { setMyCompWidth } from './actions'
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>
)
}
Cara menggulung sendiri jika Anda lebih suka:
Buat komponen pembungkus yang menangani pengambilan nilai dari DOM dan mendengarkan peristiwa pengubahan ukuran jendela (atau deteksi pengubahan ukuran komponen seperti yang digunakan oleh react-measure
). Anda memberi tahu alat peraga mana yang akan didapat dari DOM dan menyediakan fungsi render yang mengambil alat peraga tersebut sebagai anak.
Apa yang Anda render harus sudah terpasang sebelum alat peraga DOM dapat dibaca; ketika props tersebut tidak tersedia selama rendering awal, Anda mungkin ingin menggunakan style={{visibility: 'hidden'}}
sehingga pengguna tidak dapat melihatnya sebelum mendapatkan tata letak yang dihitung JS.
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);
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)}/>;
}
}
Dengan ini, menanggapi perubahan lebar sangat sederhana:
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
tempat terbaik untuk merender SVG? Kedengarannya seperti apa yang Anda inginkancomponentWillReceiveProps
ataucomponentWillUpdate
jika tidakrender
.