Estoy tratando de establecer el estado inicial en función de los datos de los accesorios.
const Calculate({data}) => { const [number, setNumber] = data === 'end' ? useState(5) : useState(0); return (...) }Esto me dio un error: React Hook "React.useState" se llama condicionalmente. Los React Hooks deben llamarse exactamente en el mismo orden en cada renderizado de componente.
Así que decidí actualizar mi código con useEffect:
const Calculate({data}) => { const [number, setNumber] = useState(0); useEffect(() => { if (data === 'end') { setNumber(5) } }, []); }Sin embargo, prefiero no establecer el estado inicialmente en cero si no es necesario.
Alternativamente, ¿puedo resolverlo haciendo que el valor inicial sea condicional?
const Calculate({data}) => { const [number, setNumber] = useState(data === 'end' ? 5 : 0); return (...) }¿Hay efectos secundarios a esto? ¿Por qué funcionaría esto y no mi intento original?
Puede usar un ternario dentro de su useState y funcionará bien. Sin embargo, es mejor envolverlo dentro de una expresión de función de la siguiente manera.
const [number, setNumber] = useState((data) => data === 'end' ? 5 : 0)La expresión de la función en el fragmento de código anterior se evaluará solo una vez mientras se establece el estado inicial. Hay una ventaja en envolver su operador ternario dentro de la expresión de la función.
Supongamos que en lugar de data === 'end' ? 5 : 0 desea usar los resultados de un cálculo costoso para establecer el estado inicial, en tal caso, puede envolverlo dentro de una expresión de función como:
const [number, setNumber] = useState(() => expensiveFunction()) Esto es mejor porque () => expensiveFunction() devolverá una función que solo se evaluará una vez durante el renderizado inicial. Mientras que si no envuelve la función expensiveFunction dentro de una expresión de función, se evaluará cada vez que su componente se represente y bloquee la ejecución del código hasta que la función expensiveFunction devuelva un valor.
Este enfoque también se conoce como Lazy initialization .
¿Hay efectos secundarios a esto? ¿Por qué funcionaría esto y no mi intento original?
No, no hay efectos secundarios, ese es el camino a seguir en su situación. No funcionó en tu caso porque violaste una de las reglas de los ganchos:
No llame a Hooks dentro de bucles, condiciones o funciones anidadas. En su lugar, siempre use Hooks en el nivel superior de su función React, antes de cualquier retorno anticipado. Al seguir esta regla, te aseguras de que los ganchos se llamen en el mismo orden cada vez que se represente un componente. Eso es lo que le permite a React preservar correctamente el estado de los Hooks entre múltiples llamadas useState y useEffect. (Si tiene curiosidad, lo explicaremos en profundidad a continuación).
Inicialmente, sus propias llamadas a useState estaban envueltas dentro de una condición y eso era un problema. Ese ya no es el caso con su nuevo enfoque.
Si los datos pueden cambiar alguna vez... Lo único que debe asegurarse de manejar es que los datos que se transmiten no son null , sino undefined si no existen.
Su useEffect debe tener data en la matriz de dependencia para volver a representar el componente ante cualquier cambio.
const Calculate({data = 0}) => { const [number, setNumber] = useState(data); useEffect(() => { setNumber(data) }, [data]); }