javascript - helmet - React.js: envolver un componente en otro
react helmet ssr (3)
Muchos lenguajes de plantilla tienen enunciados "slots" o "yield", que permiten hacer algún tipo de inversión de control para envolver una plantilla dentro de otra.
Angular tiene la opción "transcluir" .
Rails tiene declaración de rendimiento . Si React.js tuviera una declaración de rendimiento, se vería así:
var Wrapper = React.createClass({
render: function() {
return (
<div className="wrapper">
before
<yield/>
after
</div>
);
}
});
var Main = React.createClass({
render: function() {
return (
<Wrapper><h1>content</h1></Wrapper>
);
}
});
Salida deseada:
<div class="wrapper">
before
<h1>content</h1>
after
</div>
Por desgracia, React.js no tiene un <yield/>
. ¿Cómo puedo definir el componente Wrapper para lograr el mismo resultado?
La solución más simple: contenedor de tiempo de ejecución
const Wrapper = ({children}) => (
<div>
<div>header</div>
<div>{children}</div>
<div>footer</div>
</div>
);
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = () => (
<Wrapper>
<App/>
</Wrapper>
);
Esta solución es la más idiomática, pero la Wrapper
siempre tiene que renderizarse ya que recibe un nuevo accesorio para children
cada vez. No se preocupe, ciertamente está bien para el 90% de su uso).
Mejor solución: componentes de orden superior (HOC).
const wrapHOC = (WrappedComponent) => (props) => (
<div>
<div>header</div>
<div><WrappedComponent {...props}/></div>
<div>footer</div>
</div>
);
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = wrapHOC(App);
Para obtener mejores resultados, utilizar un Componente de orden superior / HOC (ahora oficialmente agregado a la documentación de React ) es mejor que los envoltorios de tiempo de ejecución porque el HOC generalmente puede cortocircuitar el procesamiento antes con shouldComponentUpdate
.
Aquí mantuve el ejemplo simple, pero obviamente, si desea aprovechar esta ganancia de rendimiento, debe usar un PureComponent
lugar de un componente funcional sin estado (que sorprendentemente no optimiza con shouldComponentUpdate
)
const wrapHOC = (WrappedComponent) => {
class Wrapper extends React.PureComponent {
render() {
return (
<div>
<div>header</div>
<div><WrappedComponent {...this.props}/></div>
<div>footer</div>
</div>
);
}
}
return Wrapper;
}
Ahora, el HOC podrá cortocircuitar la representación un paso adelante si el prop de name
no cambia.
Otros patrones de envoltura elegantes:
Los niños pueden ser cualquier cosa : puede ser sorprendente, pero usted es libre de usar lo que quiera mientras los children
apuntalan. Algo bastante común es usar la función niños .
<State initial={0}>
{(val, set) => (
<div onClick={() => set(val + 1)}>
clicked {val} times
</div>
)}
</State>
Puede obtener aún más elegante e incluso proporcionar un objeto
<Promise promise={getSomeAsyncData()}>
{{
loading: () => <div>...</div>,
success: (data) => <div>{data.something}</div>,
error: (e) => <div>{e.message}</div>,
}}
</Promise >
Los argumentos de HOC pueden ser cualquier cosa
De la misma manera, puede proporcionar parámetros adicionales a su HOC. Busque por ejemplo en connect
de react-redux que toma una función mapStateToProps
y opciones.
Incluso puede mezclar funciones para niños y HOC juntas: aquí hay un ejemplo de uso que se encuentra en el blog de fuente abierta Guillermo Rauch : HOC / Usage
export default withViews(({ views }) => (
<div>
This blog post has been viewed {views} times
.....
</div>
)
Conclusión
Los componentes de orden superior pueden brindarle un mejor rendimiento. No es tan complicado, pero al principio parece desagradable.
No migres toda la base de código a HOC después de leer esto. Solo recuerde que, en rutas críticas de su aplicación, es posible que desee utilizar HOC en lugar de envoltorios de tiempo de ejecución por motivos de rendimiento, especialmente si el mismo contenedor se utiliza muchas veces, vale la pena considerarlo como HOC.
Redux utilizó al principio una envoltura de tiempo de ejecución <Connect>
y luego cambió a una HOC connect(options)(Comp)
por motivos de rendimiento. Esta es la ilustración perfecta de lo que quería resaltar en esta respuesta.
Además de la respuesta de Sophie, también he encontrado un uso para enviar tipos de componentes secundarios, haciendo algo como esto:
var ListView = React.createClass({
render: function() {
var items = this.props.data.map(function(item) {
return this.props.delegate({data:item});
}.bind(this));
return <ul>{items}</ul>;
}
});
var ItemDelegate = React.createClass({
render: function() {
return <li>{this.props.data}</li>
}
});
var Wrapper = React.createClass({
render: function() {
return <ListView delegate={ItemDelegate} data={someListOfData} />
}
});
Tratar:
var Wrapper = React.createClass({
render: function() {
return (
<div className="wrapper">
before
{this.props.children}
after
</div>
);
}
});
Consulte Componentes múltiples: Niños y Tipo de accesorios para niños en los documentos para obtener más información.