Estos son dos estilos de codificación de código fuente de componentes de React (ponga su atención en onSubmit):

Versión 1:

...
const ContactsEditPage = ({ match }) => {
    ...

    const [updateContact] = useMutation(
        gql`mutation updateContactById ($id: UUID!, $input: ContactPatch!) {
            updateContactById(input: {id: $id, contactPatch: $input}) {
                clientMutationId
            }
        }`
    );

    return (
        ...
            <Formik
                initialValues={data.contactById}
                onSubmit={(values, actions) => {
                    updateContact({
                        variables: {
                            id: match.params.contactId,
                            input: values
                        }
                    })
                    .then(() => history.push('./'));
                }}
            >
                <Form>
                    <FieldGroup>
                        <FieldRow>
                            <FieldLabel>Email:</FieldLabel>
                            <FieldInput
                                as={Field}
                                type='email'
                                name='email'
                                placeholder='Email'
                            />
        ...
    );
};

Versión 2:

...
const ContactsEditPage = ({ match }) => {
    ...

    const [updateContact] = useMutation(
        gql`mutation updateContactById ($id: UUID!, $input: ContactPatch!) {
            updateContactById(input: {id: $id, contactPatch: $input}) {
                clientMutationId
            }
        }`
    );

    function handleContactSubmit(values) {
        updateContact({
            variables: {
                id: match.params.contactId,
                input: values
            }
        })
        .then(() => history.push('./'))
    }

    return (
        ...
            <Formik
                initialValues={data.contactById}
                onSubmit={handleContactSubmit}
            >
                <Form>
                    <FieldGroup>
                        <FieldRow>
                            <FieldLabel>Email:</FieldLabel>
                            <FieldInput
                                as={Field}
                                type='email'
                                name='email'
                                placeholder='Email'
                            />
        ...
    );
};

Las diferencias:

  • la versión 1 usa código Javascript en línea en el atributo del controlador de eventos onSubmit
  • la versión 2 usa la función handleContactSubmit en lugar del código Javascript en línea

En la primera parte de mi vida de codificación, preferí usar la función de controlador (versión 2).
Ahora tengo una preferencia por el código en línea (versión 1) cuando:

  • este código no es demasiado largo
  • y este código se usa solo una vez

Por qué: prefiero el código del controlador de eventos en línea a evitar la indirecta en el código para mejorar la legibilidad (para el proceso de revisión de codificación).

También hay un costo por usar una función (inderección). Cuando un nuevo lector encuentra este código, necesita saltar entre muchas definiciones de funciones en muchos archivos. Este proceso de lectura no lineal requiere más concentración mental que la lectura de código lineal.

Conozco a la mayoría de codificadores de ReactJS que prefieren usar la función de controlador (producir indirección en el código).

Mi pregunta:

  • ¿Soy parte de una minoría de codificadores que prefiere la indirección en el código?
  • ¿Tengo que aceptar la preferencia de la mayoría incluso si mi proceso de lectura no lineal requiere más concentración mental que leer código lineal? ¿Y agregar el uso de reglas de función de controlador en la guía de estilo ReactJS en mi proyecto?

Nota:

Saludos cordiales
Stéphane

2
Stéphane Klein 6 ago. 2020 a las 16:37

3 respuestas

La mejor respuesta

TL; DR Depende de la situación y preferencia personal.

  1. El uso de una función de flecha en el procesamiento crea una nueva función cada vez que el componente se procesa, lo que puede romper las optimizaciones basadas en una estricta comparación de identidad.

Esto solo se aplica a los componentes de la clase y no es relevante para los componentes funcionales. En un componente funcional, la función se redefine en cada renderizado independientemente de si está definida como function, const myFunc = ... o onClick={() => ...} porque tiene el alcance de su función de componente (esto podría ser resuelto con memo, pero eso está fuera del alcance de su pregunta).

  1. evite la indirecta en el código para mejorar la legibilidad humana

En mi opinión, diría que esto depende. A veces, especialmente cuando p. Ej. revisando un PR o volviendo al código que no he visto en un tiempo, me gusta ver un nombre de función en el accesorio del componente como onClick={doSomething} porque luego puedo pasar por alto el contenido que no me preocupa y enfocarme únicamente en lo que necesito hacer para la tarea en cuestión. Pero, más importante , da contexto a lo que está sucediendo a través del nombre de la función.

Sí, tiene razón en que el desarrollador tiene que desplazarse hacia abajo para ver dónde se usan las funciones y luego desplazarse hacia arriba para ver qué hace la función, pero si vi un componente con varios botones, cada uno con diferentes controladores, algo como a continuación , Tendría que leer todos los controladores hasta encontrar la función que quería modificar. Si esos fueran reemplazados por nombres de funciones, fácilmente podría entender "Oh, este botón hace esto, mientras que este otro hace aquello" sin tener que desplazarse hacia arriba para encontrar la declaración de función. Esto es especialmente cierto cuando la función es grande o compleja; volver a leer una función de 30 líneas que no tiene nombre solo para tratar de recordar lo que hace / por qué es muy doloroso cuando regresa a su código 6 meses después.

return (
  <div>
    <button onClick={() => ...}>Some text</button>
    <button onClick={() => ...}>Some other text</button>
  </div>
);

Otra cosa en la que pensar son los niveles de anidación. Si tiene un renderizado grande con muchas sangrías, y luego agrega una función compleja en línea a los accesorios, de repente debe desplazarse hacia la izquierda / derecha en su editor, lo que esencialmente reintroduce el problema original que intentó resolver.

  1. ¿Soy parte de una minoría de codificadores?

No, existen casos de uso para manejadores en línea y declarados por separado. Escribo tanto en mis repositorios, tanto dentro como fuera del trabajo. Mis compañeros hacen lo mismo.

Si el controlador es pequeño y se necesita poco esfuerzo para entender lo que hace (por ejemplo, onClick={() => location.hash = "/redirectedPage"}), entonces es totalmente razonable, y probablemente mejor para la legibilidad, usar funciones en línea (por qué declarar una nueva función redirectToPage cuando es una función de una línea?). Para funciones más complejas o componentes profundamente anidados, a menudo es útil declarar un nombre de función.

Hay otros factores que podrían entrar en juego aquí, como mantener la coherencia dentro de una base de código, reglas de pelusa, etc., pero estos son algunos de los principales que creo que se aplican fuera de ajustes específicos como esos.

1
yuyu5 6 ago. 2020 a las 15:34

TL; DR cuando no sea obvio, acuerde con su equipo sobre la base del alcance.

Algunas buenas respuestas ya se han publicado aquí y el consenso parece ser que depende de las preferencias del equipo, así como de factores "objetivos" como:

  • si es una función de una línea, prefiera en línea
  • si se está reutilizando, prefiera controladores

Pero en su ejemplo, el controlador no es ninguno de los anteriores, hace varias cosas y es un poco más complejo que una actualización de estado único. Se podría argumentar que esta complejidad justifica el uso de un controlador, o que esta no reutilización justifica un estilo en línea; es difícil trazar la línea ya que la legibilidad es bastante personal y depende de los antecedentes del desarrollador, las preferencias personales, el IDE, etc., como se explica con detalle en la respuesta de yuyu5

Es posible que su equipo no esté de acuerdo sobre qué significa lo suficientemente complejo para un manejador, pero podría estar de acuerdo en trazar la línea de acuerdo con el alcance de la función. Por ejemplo: ¿permanece dentro del componente (estado, validación de formulario, cambios de interfaz de usuario) o va más allá (almacenamiento local, inicio de sesión del usuario y, en este caso, navegación programática)?

Un acuerdo basado en el alcance (ya sea que elija el que describí u otro) es más fácil de hacer cumplir y envejecería mejor que uno basado en la complejidad, ya que los IDE y las preferencias cambian, los estilos de codificación deben seguir siendo los mismos.

1
michaelwebdev 7 ago. 2020 a las 11:39

Mi filosofía es escribir código optimizado para la legibilidad, por eso trato de mantener el render / retorno lo más abstracto posible, es más fácil volver más tarde (para depuración, nuevas características ...) y saber rápidamente desde el render / retorno lo que función hace de su nombre.

Lo que parece ser un problema de indirección es un problema falso, porque IMO:

  1. Se supone que sus archivos y directorios representan parte (grande o pequeña depende de usted) de la lógica de los componentes y / o la aplicación y, si es el caso, naturalmente busca la función correcta en el lugar correcto (el nombre debe / es se supone que es explícito).
  2. Depende de tu editor (en mi caso VScode) existen diferentes atajos que te llevan a la definición de la función / var / const ... o simplemente mediante alt-click
  3. Escribir código es siempre un WIP, por eso, incluso si no repito el código, prefiero la indirección (versión 2) porque el 90% de las veces la función se modificará en un futuro cercano, por lo que prefiero mantener todas las modificaciones en una lugar y no dentro del render.
  4. Navegar por archivos y directorios no es una opción cuando el código base crece, así que lo hará incluso si usa el estilo en línea.
  5. Es más parecido a la lógica de React y al código fuente: componentes reutilizables.
  6. Personalmente, prefiero mantener las definiciones de funciones no en el mismo lugar que el retorno / pintura / renderizado ...
  7. Se supone que es parte de su equipo / empresa, lo acordó sobre el estilo de codificación.

Para sus preguntas:

¿Soy parte de una minoría de codificadores que prefiere la indirección en el código?

Por lo que he visto, en React world la versión 2 es la preferida y la más utilizada.

¿Tengo que aceptar la preferencia de la mayoría incluso si mi proceso de lectura no lineal requiere más concentración mental que leer código lineal? ¿Y agregar el uso de reglas de función de controlador en la guía de estilo ReactJS en mi proyecto?

En mi humilde opinión, lo más importante es el equipo y lo que tiene sentido para su velocidad. Para mí no es una religión, así que mi mejor respuesta es elegir la que sea más precisa para la eficiencia de su equipo.

1
chafik bel 6 ago. 2020 a las 19:54