React에서 자동 크기 조정 된 DOM 요소의 너비에 어떻게 응답 할 수 있습니까?
React 구성 요소를 사용하는 복잡한 웹 페이지가 있으며 페이지를 정적 레이아웃에서 더 반응이 빠르고 크기를 조정할 수있는 레이아웃으로 변환하려고합니다. 그러나 저는 React로 계속 한계에 부딪히며 이러한 문제를 처리하는 표준 패턴이 있는지 궁금합니다. 내 특정 경우에는 display : table-cell 및 width : auto를 사용하여 div로 렌더링되는 구성 요소가 있습니다.
안타깝게도 구성 요소의 너비를 쿼리 할 수 없습니다. 실제로 DOM에 배치하지 않는 한 요소의 크기를 계산할 수 없기 때문입니다 (실제 렌더링 된 너비를 추론 할 전체 컨텍스트가 있음). 상대 마우스 위치와 같은 용도로 사용하는 것 외에도 구성 요소 내의 SVG 요소에 너비 속성을 올바르게 설정하려면이 기능이 필요합니다.
또한 창 크기가 조정될 때 설치 중에 한 구성 요소에서 다른 구성 요소로 크기 변경을 어떻게 전달합니까? shouldComponentUpdate에서 모든 타사 SVG 렌더링을 수행하고 있지만 해당 메서드 내에서 자신이나 다른 하위 구성 요소에 상태 나 속성을 설정할 수 없습니다.
React를 사용하여이 문제를 처리하는 표준 방법이 있습니까?
가장 실용적인 해결책은 react-measure 를 사용 하는 것 입니다.
참고 :이 코드는 react-measure@^2.0.0
API가 변경되었으므로 작동하지 않습니다 . 새 API를 보려면 위 링크를 방문하세요.
import Measure from 'react-measure'
const MeasuredComp = () => (
<Measure>
{({width}) => <div>My width is {width}</div>}
</Measure>
)
컴포넌트 간의 크기 변경을 전달하려면 onMeasure
콜백을 전달하고 수신 한 값을 어딘가에 저장할 수 있습니다 (요즘 상태를 공유하는 표준 방법은 Redux 를 사용하는 것입니다 ).
import Measure from 'react-measure'
import connect from 'react-redux'
import {setMyCompWidth} from './actions' // some action that stores width in somewhere in redux state
function select(state) {
return {
currentWidth: ... // get width from somewhere in the state
}
}
const MyComp = connect(select)(({dispatch, currentWidth}) => (
<Measure onMeasure={({width}) => dispatch(setMyCompWidth(width))}>
<div>MyComp width is {currentWidth}</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>
);
나는 당신이 찾고있는 수명주기 방법이 componentDidMount
. 요소는 이미 DOM에 배치되었으며 구성 요소의 refs
.
예를 들면 :
var Container = React.createComponent({
componentDidMount: function () {
// if using React < 0.14, use this.refs.svg.getDOMNode().offsetWidth
var width = this.refs.svg.offsetWidth;
},
render: function () {
<svg ref="svg" />
}
});
couchand 솔루션 대신 findDOMNode를 사용할 수 있습니다.
var Container = React.createComponent({
componentDidMount: function () {
var width = React.findDOMNode(this).offsetWidth;
},
render: function () {
<svg />
}
});
내가 작성한 I 라이브러리를 사용하여 렌더링 된 구성 요소 크기를 모니터링하고이를 통해 전달할 수 있습니다.
예를 들면 :
import SizeMe from 'react-sizeme';
class MySVG extends Component {
render() {
// A size prop is passed into your component by my library.
const { width, height } = this.props.size;
return (
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
);
}
}
// Wrap your component export with my library.
export default SizeMe()(MySVG);
데모 : https://react-sizeme-example-esbefmsitg.now.sh/
Github : https://github.com/ctrlplusb/react-sizeme
그것은 내가 나보다 훨씬 영리한 사람들에게서 빌린 최적화 된 스크롤 / 객체 기반 알고리즘을 사용합니다. :)
'developer tip' 카테고리의 다른 글
Github Commit RSS 피드 설정 (0) | 2020.09.19 |
---|---|
문자열을 변수 이름으로 변환하려면 (0) | 2020.09.19 |
Windows에서 CMD의 'ls'이 (가) 인식되지 않음 (0) | 2020.09.19 |
GitHub에서 내 pull 요청을 어디에서 볼 수 있습니까? (0) | 2020.09.19 |
입력이 완전 제곱인지 확인하는 좋은 알고리즘은 무엇입니까? (0) | 2020.09.19 |