Estoy tratando de convertir esta genial <canvas>
animación 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 function Ball()
.
Por motivos de rendimiento, probablemente sería mejor convertirlos 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 funciones this.update()
y this.draw
que se definen en function Ball()
.
¿Las funciones de los componentes sin estado van dentro o fuera del componente? En otras palabras, ¿cuál de las siguientes opciones 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 / contras de cada uno? ¿Uno de ellos es mejor para casos de uso específicos como el mío?
Respuestas:
Lo primero que hay que tener en cuenta es que los componentes funcionales sin estado no pueden tener métodos, no debe contar con llamar
update
odraw
renderizarBall
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 que las declare solo una vez y siempre reutilice la misma referencia. Cuando declaras la función en el interior, cada vez que se renderiza el componente, la función se volverá a definir.
Hay casos en los que necesitará definir una función dentro del componente para, por ejemplo, asignarla como un controlador de eventos que se comporta de manera diferente según las propiedades del componente. Pero aún así, podría definir la función fuera
Ball
y vincularla con las propiedades, haciendo que el código sea mucho más limpio y haciendo que las funcionesupdate
o seandraw
reutilizables.// You can use update somewhere else const update (propX, a, b) => { ... }; const Ball = props => ( <Something onClick={update.bind(null, props.x)} /> );
Si está usando ganchos , puede usar
useCallback
para asegurarse de que la función solo se redefina cuando una de sus dependencias (props.x
en este caso) cambia: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 forma incorrecta :
const Ball = props => { function update(a, b) { // props.x is visible here } return ( <Something onClick={update} /> ); }
A la hora de usar
useCallback
, definir laupdate
función en eluseCallback
propio hook fuera del componente se convierte en una decisión de diseño más que nada, debes tener en cuenta si vas a reutilizarupdate
y / o si necesitas acceder al alcance del 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 la ingeniería excesiva 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 fines 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.fuente
this.draw
función dentro deBall
. Utiliza elctx
de lo que sería el componente principal<canvas>
y también utiliza lathis
palabra clave para lo que sería elBall
componente secundario . ¿Cuál sería la mejor manera de integrar la implementación del componente sin estado para que ambas propiedades sean accesibles?this
cuando se utilizan componentes funcionales sin estado, tenlo en cuenta. Para el contexto del lienzo, tendrías que pasarlo a cada unoBall
, eso no suena nada bien.bind
específicamente en Chrome antes de 59 era incluso más lento que las funciones de flecha. Y en Firefox también ha pasado bastante tiempo ya que ambos funcionan con la misma velocidad. Entonces, diría que en tales casos no hay diferencia cuál es la forma preferida :)Something
componente sepa que hay un prop X en su componente padre, ya que lo hace consciente de su contexto. Lo mismo ocurre con la pregunta que está haciendo y el código de muestra que he escrito, depende del contexto, que se ignora por simplicidad.Podemos tener funciones dentro de componentes funcionales sin estado, a continuación se muestra el ejemplo:
const 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 llame al componente.fuente
handlePick()
arriba / fuera del componente como sifunction handlePick() { ... }; const Action = () => { ... }
el resultado fuera que handlePick solo se define una vez. Si necesita datos delAction
componente, debe pasarlos como parámetros a lahandlePick
función.Podemos usar el gancho React
useCallback
como se muestra a continuación en un componente funcional:const home = (props) => { const { small, img } = props const [currentInd, setCurrentInd] = useState(0); const imgArrayLength = img.length - 1; useEffect(() => { let id = setInterval(() => { if (currentInd < imgArrayLength) { setCurrentInd(currentInd => currentInd + 1) } else { setCurrentInd(0) } }, 5000); return () => clearInterval(id); }, [currentInd]); const onLeftClickHandler = useCallback( () => { if (currentInd === 0) { } else { setCurrentInd(currentInd => currentInd - 1) } }, [currentInd], ); const onRightClickHandler = useCallback( () => { if (currentInd < imgArrayLength) { setCurrentInd(currentInd => currentInd + 1) } else { } }, [currentInd], ); return ( <Wrapper img={img[currentInd]}> <LeftSliderArrow className={currentInd > 0 ? "red" : 'no-red'} onClick={onLeftClickHandler}> <img src={Icon_dir + "chevron_left_light.png"}></img> </LeftSliderArrow> <RightSliderArrow className={currentInd < imgArrayLength ? "red" : 'no-red'} onClick={onRightClickHandler}> <img src={Icon_dir + "chevron_right_light.png"}></img> </RightSliderArrow> </Wrapper>); } export default home;
Obtengo 'img' de su padre y esa es una matriz.
fuente
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 },[]) }
Por otro lado, si no desea utilizar props o state in function, defínalo fuera del componente.
const computeSomethings=()=>{ // Do some things with params or side effects } function Component(props){ }
fuente