Предпочитаете встроенный обработчик событий, чтобы избежать косвенного обращения в код для улучшения читабельности, или использовать функцию обработчика? - PullRequest
2 голосов
/ 06 августа 2020

Это два стиля кодирования исходного кода компонентов React (обратите внимание на onSubmit):

Версия 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'
                            />
        ...
    );
};

Версия 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'
                            />
        ...
    );
};

Отличия:

  • версия 1 использует встроенный Javascript код в атрибуте обработчика событий onSubmit
  • версия 2 использует функцию handleContactSubmit вместо встроенного Javascript код

В первой части моей жизни программирования я предпочитал использовать функцию обработчика (версия 2). Теперь я предпочитаю встроенный код (версия 1), когда:

  • этот код не слишком длинный
  • и этот код используется только один раз

Почему: я предпочитаю код встроенного обработчика событий, а не избегать косвенного обращения в коде, чтобы улучшить удобочитаемость (для процесса проверки кода).

Существует также стоимость использования функции (отступление). Когда новый читатель сталкивается с этим кодом, ему нужно переключаться между определениями многих функций во многих файлах. Этот процесс нелинейного чтения требует большего умственного внимания, чем чтение линейного кода.

Я встречаю большинство ReactJS программистов, которые предпочитают использовать функцию обработчика (производить косвенное обращение в коде).

Мой вопрос:

  • Являюсь ли я частью меньшинства программистов, которое предпочитает косвенный код?
  • Должен ли я соглашаться с предпочтениями большинства, даже если мой нелинейный процесс чтения требует большего умственное внимание, чем чтение линейного кода? И добавить использование правила функции обработчика в руководство по стилю ReactJS в моем проекте?

Примечание:

С уважением, Стефан

Ответы [ 3 ]

1 голос
/ 06 августа 2020

Моя философия - писать код, оптимизированный для удобочитаемости, поэтому я стараюсь делать рендеринг / возврат как можно более абстрактным, легче вернуться позже (для отладки, новых функций ...) и быстро узнать из рендера / вернуть то, что функция делает из своего имени.

То, что кажется проблемой косвенного обращения, является ложной проблемой, потому что IMO:

  1. Ваши файлы и каталоги должны представлять часть (большой или маленький зависит от вас) logi c компонентов и / или приложения, и если это так, вы, естественно, ищете правильную функцию в нужном месте (именование должно / должно быть явным).
  2. Это зависит от вашего редактора (в моем случае VScode) есть разные ярлыки, которые приводят вас к определению функции / var / const ... или просто щелчком alt
  3. Writing код всегда является WIP, поэтому, даже если я не повторяю код, я предпочитаю косвенное обращение (версия 2), потому что в 90% случаев функция будет изменена в В ближайшем будущем, поэтому я предпочитаю хранить все модификации в одном месте, а не в рендере.
  4. Навигация по файлам и каталогам невозможна, когда базовый код растет, поэтому вы будете делать это, даже если вы используйте встроенный стиль.
  5. Это больше похоже на React logi c и исходный код: компоненты многократного использования.
  6. Я лично предпочитаю хранить определения функций не в том же месте, что и возврат / рисование /rendering...
  7. Он / должен быть частью вашей команды / компании, согласовал стиль кодирования.

По вашим вопросам:

Я принадлежу к меньшинству программистов, которые предпочитают косвенный код в коде?

Из того, что я видел, в React world версия 2 является предпочтительной и наиболее часто используемой.

Должен ли я соглашаться с предпочтениями большинства, даже если мой процесс нелинейного чтения требует большей умственной концентрации, чем чтение линейного кода? И добавить использование правила функции обработчика в руководство по стилю ReactJS в моем проекте?

ИМХО, самое важное - это команда и то, что имеет смысл с ее скоростью. Для меня это не религия, поэтому мой лучший ответ - выбрать тот, который более соответствует эффективности вашей / вашей команды.

1 голос
/ 07 августа 2020

TL; DR, когда неочевидно, согласитесь с вашей командой в зависимости от объема.

Здесь уже были опубликованы некоторые хорошие ответы, и, похоже, все согласны с тем, что это также зависит от предпочтений команды в качестве "объективных" факторов, таких как:

  • , если это однострочная функция, предпочитать встроенную
  • , если она используется повторно, предпочитать обработчики

Но в вашем примере обработчик не относится к abov, выполняет несколько задач и немного сложнее, чем обновление одного состояния. Можно утверждать, что эта сложность оправдывает использование обработчика, или невозможность повторного использования оправдывает встроенный стиль; трудно провести черту, так как удобочитаемость является довольно личной и зависит от опыта разработчика, личных предпочтений, IDE и т. д. c. как подробно описано в ответе yuyu5

Ваша команда может не согласиться с тем, что означает «достаточно сложный для обработчика», но может договориться о проведении линии в соответствии с объемом функция. Например: остается ли он внутри компонента (состояние, проверка формы, изменения пользовательского интерфейса) или выходит за рамки (локальное хранилище, вход пользователя в систему и, в данном случае, программирование c навигации)?

A Соглашение на основе области действия (независимо от того, выберете ли вы тот, который я описал, или другое) легче обеспечить, и оно будет стареть лучше, чем соглашение, основанное на сложности, поскольку IDE и предпочтения меняются, стили кодирования должны оставаться прежними.

1 голос
/ 06 августа 2020

TL; DR Это зависит от ситуации и личных предпочтений.

  1. Использование функции стрелки в рендере создает новую функцию каждый раз при рендеринге компонента, что может нарушить оптимизацию на основе строгого сравнения идентичности.

Это применимо только к компонентам класса и не актуально для функциональных компонентов. В функциональном компоненте функция переопределяется при каждой визуализации независимо от того, определена ли она как function, const myFunc = ... или onClick={() => ...}, потому что она привязана к вашей компонентной функции (это можно решить с помощью memo, но это выходит за рамки вашего вопроса).

избегайте косвенного обращения в коде, чтобы улучшить удобочитаемость

ИМО, я бы сказал, это зависит от обстоятельств. Иногда, особенно когда, например, просматривая PR или возвращаясь к коду, который я не видел некоторое время, мне нравится видеть имя функции в опоре компонента, например onClick={doSomething}, потому что тогда я могу пролистать контент, который меня не касается, и сосредоточьтесь исключительно на том, что мне нужно сделать для выполнения поставленной задачи. Но, , что более важно , он дает контекст тому, что происходит, через имя функции.

Да, вы правы, разработчику нужно прокрутить вниз, чтобы увидеть, где используются функции, и затем прокрутите назад, чтобы увидеть, что делает функция, но если бы я увидел компонент с несколькими кнопками, каждая с разными обработчиками, что-то вроде ниже, мне пришлось бы фактически читать каждый обработчик, пока я не нашел функцию, которую хотел изменить. Если бы вместо них они были заменены именами функций, я мог бы легко понять: «О, эта кнопка делает то же самое, а эта другая делает то же самое» без необходимости прокручивать вверх, чтобы найти объявление функции. Это особенно верно, когда функция является большой или сложной; перечитать 30-строчную функцию, у которой нет имени, просто чтобы попытаться вспомнить, что она делает / почему это очень болезненно, когда вы возвращаетесь к своему коду через 6 месяцев.

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

Еще одна вещь, о которой следует подумать, - это уровни гнездования. Если у вас большой рендер со множеством отступов, а затем вы добавляете сложную функцию, встроенную в реквизиты, внезапно вам приходится прокручивать в редакторе влево / вправо, что по существу заново вводит исходную проблему, которую вы пытались решить.

Являюсь ли я частью меньшинства кодировщиков?

Нет, есть варианты использования как для встроенных, так и для отдельно объявленных обработчиков. Я пишу как в свои репозитории, так и не на работе. Мои товарищи по команде делают то же самое.

Если обработчик небольшой и не требуется больших усилий, чтобы понять, что он делает (например, onClick={() => location.hash = "/redirectedPage"}), то вполне разумно и, вероятно, лучше для удобочитаемости, использовать встроенные функции ( зачем объявлять новую функцию redirectToPage, если это однострочная функция?). Для более сложных функций или глубоко вложенных компонентов часто бывает полезно объявить имя функции.

Здесь могут быть задействованы и другие факторы, такие как поддержание согласованности в базе кода, правила lint и т. Д. c., Но это некоторые из основных, которые, как мне кажется, применимы вне определенных c настроек, подобных этим.

...