Estoy tratando de convertir esta genial animación <canvas> que encontré aquí en un componente reutilizable de React. Parece que este componente requeriría un componente principal para el lienzo y muchos componentes secundarios para la function Ball() .
Probablemente sería mejor, por razones de rendimiento, convertir las Balls en componentes sin estado, ya que habrá muchos de ellos. No estoy tan familiarizado con la creación de componentes sin estado y me preguntaba dónde debería definir las this.update() y this.draw definidas en function Ball() .
¿Las funciones para los componentes sin estado van dentro o fuera del componente? En otras palabras, ¿cuál de los siguientes es mejor?
1:
const Ball = (props) => { const update = () => { ... } const draw = () => { ... } return ( ... ); }2:
function update() { ... } function draw() { ... } const Ball = (props) => { return ( ... ); }¿Cuáles son los pros y los contras de cada uno? ¿Cuál de ellos es mejor para casos de uso específicos como el mío?
Lo primero que debe tener en cuenta es que los componentes funcionales sin estado no pueden tener métodos, no debe contar con llamar a update o draw en una Ball renderizada si es un componente funcional sin estado.
En la mayoría de los casos, debe declarar las funciones fuera de la función del componente para declararlas solo una vez y siempre reutilizar la misma referencia. Cuando declaras la función dentro, cada vez que se representa el componente, la función se definirá nuevamente.
Hay casos en los que necesitará definir una función dentro del componente para, por ejemplo, asignarla como un controlador de eventos que se comporte de manera diferente según las propiedades del componente. Pero aún podría definir la función fuera de Ball y vincularla con las propiedades, haciendo que el código sea mucho más limpio y que las funciones de update o draw sean reutilizables.
// You can use update somewhere else const update (propX, a, b) => { ... }; const Ball = props => ( <Something onClick={update.bind(null, props.x)} /> ); Si usa ganchos , puede usar useCallback para asegurarse de que la función solo se redefina cuando cambie una de sus dependencias ( props.x en este caso):
const Ball = props => { const onClick = useCallback((a, b) => { // do something with a, b and props.x }, [props.x]); return ( <Something onClick={onClick} /> ); }Esta es la manera incorrecta :
const Ball = props => { function update(a, b) { // props.x is visible here } return ( <Something onClick={update} /> ); } Al usar useCallback , definir la función de update en el gancho useCallback en sí mismo fuera del componente se convierte en una decisión de diseño más que nada, debe tener en cuenta si va a reutilizar la update y/o si necesita acceder al alcance de la cierre del componente para, por ejemplo, leer/escribir en el estado. Personalmente, elijo definirlo dentro del componente de forma predeterminada y hacerlo reutilizable solo si surge la necesidad, para evitar el exceso de ingeniería desde el principio. Además de eso, es mejor reutilizar la lógica de la aplicación con ganchos más específicos, dejando los componentes para propósitos de presentación. Definir la función fuera del componente mientras se usan ganchos realmente depende del grado de desacoplamiento de React que desee para la lógica de su aplicación.
Puede colocar funciones dentro de componentes funcionales sin estado:
function Action() { function handlePick(){ alert("test"); } return ( <div> <input type="button" onClick={handlePick} value="What you want to do ?" /> </div> ) } Pero no es una buena práctica ya que la función handlePick() se definirá cada vez que se represente el componente.
Sería mejor definir la función fuera del componente:
function handlePick(){ alert("test"); } function Action() { return ( <div> <input type="button" onClick={handlePick} value="What you want to do ?" /> </div> ) }Si desea usar accesorios o el estado del componente en la función, eso debe definirse en el componente con useCallback.
function Component(props){ const onClick=useCallback(()=>{ // Do some things with props or state },[]) return <Something {...{onClick}} /> }Por otro lado, si no quiere usar accesorios o estado en la función, defínalo fuera del componente.
const computeSomethings=()=>{ // Do some things with params or side effects } function Component(props){ return <Something onClick={computeSomethings} /> }Para las etiquetas HTML, no necesita useCallback porque eso se manejará en el lado de reacción y no se asignará a HTML
function Component(props){ const onClick=()=>{ // Do some things with props or state } return <Something {...{onClick}} /> }Editar: funciones en ganchos
Para la función de uso en ganchos, por ejemplo, useEffect, mi sugerencia es definir la función dentro de useEffect, si está preocupado por DRY, haga que su función sea pura, llámela en gancho y dele sus parámetros. ¿Qué pasa con los anzuelos? Debería / podría agregar todos sus parámetros a las dependencias de ganchos, pero useEffect solo necesita dependencias que deberían afectar los cambios.