javascript - tutorial - react con base de datos
¿Cómo puedo responder al ancho de un elemento DOM de tamaño automático en React? (4)
Tengo una página web compleja que usa los componentes de React y estoy tratando de convertir la página de un diseño estático a un diseño más receptivo y de tamaño variable. Sin embargo, sigo encontrando limitaciones con React, y me pregunto si existe un patrón estándar para manejar estos problemas. En mi caso específico, tengo un componente que se representa como un div con display: table-cell y width: auto.
Desafortunadamente, no puedo consultar el ancho de mi componente, porque no puedes calcular el tamaño de un elemento a menos que esté realmente ubicado en el DOM (que tiene el contexto completo para deducir el ancho real). Además de usar esto para cosas como el posicionamiento relativo del mouse, también necesito esto para establecer correctamente los atributos de ancho en los elementos SVG dentro del componente.
Además, cuando la ventana cambia de tamaño, ¿cómo comunico los cambios de tamaño de un componente a otro durante la instalación? Estamos haciendo todo nuestro renderizado SVG de terceros en shouldComponentUpdate, pero no puedes establecer el estado o las propiedades en ti o en otros componentes secundarios dentro de ese método.
¿Existe una forma estándar de tratar este problema usando React?
Alternativamente a la solución couchand puede usar findDOMNode
var Container = React.createComponent({
componentDidMount: function () {
var width = React.findDOMNode(this).offsetWidth;
},
render: function () {
<svg />
}
});
Creo que el método del ciclo de vida que estás buscando es componentDidMount
. Los elementos ya se han colocado en el DOM y puede obtener información sobre ellos desde los refs del componente.
Por ejemplo:
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" />
}
});
La solución más práctica es usar github.com/souporserious/react-measure .
Nota : este código no funciona con react-measure@^2.0.0
ya que la API ha cambiado. Visita el enlace de arriba para ver la nueva API.
import Measure from ''react-measure''
const MeasuredComp = () => (
<Measure>
{({width}) => <div>My width is {width}</div>}
</Measure>
)
Para comunicar los cambios de tamaño entre los componentes, puede pasar una onMeasure
llamada onMeasure
y almacenar los valores que recibe en algún lugar (la forma estándar de compartir el estado en estos días es usar 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>
))
Cómo hacer su propia versión si realmente prefiere:
Cree un componente envoltorio que maneje la obtención de valores desde el DOM y la escucha de los eventos de cambio de tamaño de la ventana (o la detección de cambio de tamaño del componente tal como lo utiliza react-measure
). Usted le dice qué accesorios debe obtener del DOM y proporciona una función de renderizado teniendo esos accesorios como un niño.
Lo que renderiza debe montarse antes de poder leer los objetos del DOM; cuando esos accesorios no están disponibles durante el render inicial, es posible que desee utilizar style={{visibility: ''hidden''}}
para que el usuario no pueda verlo antes de obtener un diseño calculado por 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)}/>;
}
}
Con esto, responder a los cambios de ancho es muy simple:
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>
);
Puede usar la biblioteca I que escribí, que monitorea el tamaño de sus componentes y se la pasa a usted.
Por ejemplo:
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);
Demostración: https://react-sizeme-example-esbefmsitg.now.sh/
Github: https://github.com/ctrlplusb/react-sizeme
Utiliza un algoritmo optimizado basado en desplazamiento / objeto que pedí prestado a personas mucho más inteligentes que yo. :)