การแก้ปัญหาการปฏิบัติมากที่สุดคือการใช้ห้องสมุดสำหรับเช่นนี้ตอบสนองวัด
ปรับปรุง : ตอนนี้จะมีตะขอที่กำหนดเองสำหรับการตรวจสอบการปรับขนาด (ซึ่งผมไม่ได้พยายามส่วนตัว): ตอบสนองปรับขนาดตระหนักถึง 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'
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>
)
}
วิธีการม้วนของคุณเองหากคุณต้องการ:
สร้างคอมโพเนนต์ Wrapper ที่จัดการการรับค่าจาก DOM และการรับฟังเหตุการณ์การปรับขนาดหน้าต่าง (หรือการตรวจจับการปรับขนาดคอมโพเนนต์ที่ใช้โดย react-measure
) คุณบอกได้ว่าอุปกรณ์ประกอบฉากใดที่จะได้รับจาก DOM และจัดเตรียมฟังก์ชันการเรนเดอร์โดยนำอุปกรณ์ประกอบฉากเหล่านั้นมาเป็นเด็ก
สิ่งที่คุณแสดงจะต้องติดตั้งก่อนที่จะอ่านอุปกรณ์ประกอบฉาก DOM เมื่ออุปกรณ์ประกอบฉากเหล่านั้นไม่สามารถใช้งานได้ในระหว่างการเรนเดอร์ครั้งแรกคุณอาจต้องการใช้style={{visibility: 'hidden'}}
เพื่อให้ผู้ใช้มองไม่เห็นก่อนที่จะได้รับเลย์เอาต์ที่คำนวณด้วย 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)}/>;
}
}
ด้วยสิ่งนี้การตอบสนองต่อการเปลี่ยนแปลงความกว้างทำได้ง่ายมาก:
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
เป็นสถานที่ที่ดีที่สุดในการแสดง SVG มันเสียงเหมือนสิ่งที่คุณต้องการเป็นcomponentWillReceiveProps
หรือถ้าไม่ได้componentWillUpdate
render