Простые советы по написанию чистых компонентов React

Простые советы по написанию чистых компонентов React

От создателя: в этом посте давайте разглядим несколько обычных советов, которые посодействуют для вас писать наиболее незапятнанные составляющие React и лучше масштабировать проект.

Опасайтесь передачи параметров c помощью оператора разделения

Давайте поначалу начнем с антипаттерна, которого для вас следует избегать. Если нет определенной и обоснованной предпосылки, чтоб создать это, вы должны избегать прохождения параметров вниз дерева компонентов, используя оператор разделения, к примеру, так: {…props}.

Таковая передача параметров вправду ускоряет написание компонентов. Но она также затрудняет выявление ошибок в коде. Вы теряете уверенность в собственных компонентах, что затрудняет их рефакторинг, и в итоге ошибки начнут появляться намного ранее.

Оберните характеристики функций в объект

Если ваша функция воспринимает несколько характеристик, рекомендуется заключить их в объект. Вот вам наглядный пример:

JavaScript

123export const sampleFunction = ({ param1, param2, param3 }) => {    console.log({ param1, param2, param3 });}

Таковой метод написания функции дает несколько приметных преимуществ:

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

Для редакторов с настроенным IntelliSense вы получите автозаполнение для аргументов функции.

Для обработчиков событий используйте функции, возвращающие функции обработчика

Если вы знакомы с многофункциональным программированием, этот способ припоминает каррирование, так как вы заблаговременно устанавливаете некие характеристики. Давайте разглядим пример:

JavaScript

12345678910111213export default function SampleComponent({ onValueChange }) {    const handleChange = (key) => {        return (e) => onValueChange(key, e.target.value)    }     return (        <form>            <input onChange={handleChange(‘name’)} />            <input onChange={handleChange(’email’)} />            <input onChange={handleChange(‘phone’)} />        </form>    )}

Видите ли, написав таковым образом функции-обработчики, вы сможете сохранить дерево компонентов наиболее незапятнанным.

Использйте map заместо if / else

Когда для вас необходимо показать разные элементы на базе пользовательской логики, я предлагаю применять map заместо операторов if / else. Вот вам наглядный пример использования if / else:

JavaScript

12345678910111213141516171819const Student = ({ name }) => <p>Student name: {name}</p>const Teacher = ({ name }) => <p>Teacher name: {name}</p>const Guardian = ({ name }) => <p>Guardian name: {name}</p>  export default function SampleComponent({ user }) {    let Component = Student;    if (user.type === ‘teacher’) {        Component = Teacher    } else if (user.type === ‘guardian’) {        Component = Guardian    }     return (        <div>            <Component name={user.name} />        </div>    )}
READ
Intersection Observer API позволяет сделать отложенную загрузку моментальной

А вот вам наглядный пример использования map:

JavaScript

123456789101112131415161718192021import React from ‘react’ const Student = ({ name }) => <p>Student name: {name}</p>const Teacher = ({ name }) => <p>Teacher name: {name}</p>const Guardian = ({ name }) => <p>Guardian name: {name}</p> const COMPONENT_MAP = {    student: Student,    teacher: Teacher,    guardian: Guardian} export default function SampleComponent({ user }) {    const Component = COMPONENT_MAP[user.type]     return (        <div>            <Component name={user.name} />        </div>    )}

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

Хуки компонентов

Считаю этот паттерн полезным, если вы не злоупотребляете им. Вы сможете найти, что используете некие составляющие во всем собственном приложении. Если им для работы требуется состояние, вы сможете обернуть их хуком, обеспечивающим это состояние. Неплохими примерами таковых компонентов являются всплывающие окна, всплывающие извещения либо обыкновенные модальные окна. К примеру, вот хук компонента для обычного модального окна доказательства:

JavaScript

12345678910111213141516171819202122232425262728293031323334353637import ConfirmationDialog from ‘components/global/ConfirmationDialog’; export default function useConfirmationDialog({    headerText,    bodyText,    confirmationButtonText,    onConfirmClick,}) {     const [isOpen, setIsOpen] = useState(false);     const onOpen = () => {        setIsOpen(true);    };       const Dialog = useCallback(        () => (            <ConfirmationDialog                headerText={headerText}                bodyText={bodyText}                isOpen={isOpen}                onConfirmClick={onConfirmClick}                onCancelClick={() => setIsOpen(false)}                confirmationButtonText={confirmationButtonText}            />        ),        [isOpen]    );     return {        Dialog,        onOpen,    }; }

Потом вы сможете применять собственный компонентный хук так:

JavaScript

123456789101112131415161718192021222324252627282930import React from «react»;import { useConfirmationDialog } from ‘./useConfirmationDialog’ function Client() {  const { Dialog, onOpen } = useConfirmationDialog({    headerText: «Delete this record?»,    bodyText:      «Are you sure you want delete this record? This cannot be undone.»,    confirmationButtonText: «Delete»,    onConfirmClick: handleDeleteConfirm,  });    function handleDeleteConfirm() {    //TODO: delete  }   const handleDeleteClick = () => {    onOpen();  };   return (    <div>      <Dialog />      <button onClick={handleDeleteClick} />    </div>  );} export default Client;

Такое абстрагирование компонента устраняет вас от написания огромного количества шаблонного кода управления состоянием.

Разделение компонентов

Последующие три совета относятся к разумному разделению компонентов. По моему опыту, сохранение маленьких размеров компонентов — наилучший метод сохранить маневренность проекта.

READ
Поисковую выдачу Google будет трясти из-за May 2020 Core Update

Используйте обертки

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

Вот вам наглядный пример компонента, который реализует перетаскивание при помощи response-beautiful-dnd:

JavaScript

123456789101112131415161718192021222324252627282930313233343536373839404142import React from ‘react’import { DragDropContext, Droppable } from ‘react-beautiful-dnd’;  export default function DraggableSample() {    function handleDragStart(result) {        console.log({ result });    }     function handleDragUpdate({ destination })         console.log({ destination });    }     const handleDragEnd = ({ source, destination }) => {        console.log({ source, destination });    };     return (        <div>            <DragDropContext                onDragEnd={handleDragEnd}                onDragStart={handleDragStart}                onDragUpdate={handleDragUpdate}            >                <Droppable droppableId=»droppable» direction=»horizontal»>                    {(provided) => (                        <div {…provided.droppableProps} ref={provided.innerRef}>                            {columns.map((column, index) => {                                return (                                    <ColumnComponent                                        key={index}                                        column={column}                                    />                                );                            })}                        </div>                    )}                </Droppable>            </DragDropContext>        </div>    )}

Сейчас проверьте компонент опосля того, как мы переместили всю логику перетаскивания в компонент-оболочку:

JavaScript

123456789101112131415161718import React from ‘react’ export default function DraggableSample() {    return (        <div>            <DragWrapper>                {columns.map((column, index) => {                    return (                        <ColumnComponent                            key={index}                            column={column}                        />                    );                })}            </DragWrapper>        </div>    )}

А вот код оболочки:

JavaScript

1234567891011121314151617181920212223242526272829303132import React from ‘react’import { DragDropContext, Droppable } from ‘react-beautiful-dnd’; export default function DragWrapper({children}) {    function handleDragStart(result) {        console.log({ result });    }     function handleDragUpdate({ destination }) {        console.log({ destination });    }     const handleDragEnd = ({ source, destination }) => {        console.log({ source, destination });    };     return (        <DragDropContext            onDragEnd={handleDragEnd}            onDragStart={handleDragStart}            onDragUpdate={handleDragUpdate}        >            <Droppable droppableId=»droppable» direction=»horizontal»>                {(provided) => (                    <div {…provided.droppableProps} ref={provided.innerRef}>                        {children}                    </div>                )}            </Droppable>        </DragDropContext>    )}

В итоге легче посмотреть на компонент и осознать, что он делает на высочайшем уровне. Вся функциональность перетаскивания находится в оболочке, и её легче осознать.

Разделение задач

Это мой возлюбленный способ разделения огромных компонентов. В контексте React разделение задач значит разделение частей компонентов, отвечающих за подборку и изменение данных, и частей, отвечающих только за отображение дерева частей.

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

К примеру, разглядим компонент:

JavaScript

123456789101112131415161718192021222324252627282930313233343536373839import React from ‘react’import { someAPICall } from ‘./API’import ItemDisplay from ‘./ItemDisplay’  export default function SampleComponent() {    const [data, setData] = useState([])     useEffect(() => {        someAPICall().then((result) => {            setData(result)        })    }, [])     function handleDelete() {        console.log(‘Delete!’);    }     function handleAdd() {        console.log(‘Add!’);    }     const handleEdit = () => {        console.log(‘Edit!’);    };     return (        <div>            <div>                {data.map(item => <ItemDisplay item={item} />)}            </div>            <div>                <button onClick={handleDelete} />                <button onClick={handleAdd} />                <button onClick={handleEdit} />            </div>        </div>    )}

Сейчас вот его реорганизованная версия с разделением кода при помощи пользовательских хуков:

JavaScript

12345678910111213141516171819import React from ‘react’import ItemDisplay from ‘./ItemDisplay’ export default function SampleComponent() {    const { data, handleDelete, handleEdit, handleAdd } = useCustomHook()     return (        <div>            <div>                {data.map(item => <ItemDisplay item={item} />)}            </div>            <div>                <button onClick={handleDelete} />                <button onClick={handleAdd} />                <button onClick={handleEdit} />            </div>        </div>    )}

А вот и сам хук:

JavaScript

1234567891011121314151617181920212223242526import { someAPICall } from ‘./API’  export const useCustomHook = () => {    const [data, setData] = useState([])     useEffect(() => {        someAPICall().then((result) => {            setData(result)        })    }, [])     function handleDelete() {        console.log(‘Delete!’);    }     function handleAdd() {        console.log(‘Add!’);    }     const handleEdit = () => {        console.log(‘Edit!’);    };     return { handleEdit, handleAdd, handleDelete, data }}

Отдельный файл для всякого компонента

Нередко люди пишут таковой код:

JavaScript

1234567891011121314151617181920import React from ‘react’  export default function SampleComponent({ data }) {     export const ItemDisplay = ({ name, date }) => (        <div>            <h3>{name}</h3>            <p>{date}</p>        </div>    )     return (        <div>            <div>                {data.map(item => <ItemDisplay item={item} />)}            </div>        </div>    )}

Хотя в написании такового кода нет ничего отвратительного, следовать ему не рекомендуется. У перевода ItemDisplay в отдельный файл нет недочетов, а плюсы состоят в том, что ваши составляющие слабо соединены и их легче расширять.

Написание незапятнанного кода по большей части сводится к тому, чтоб быть внимательным и отыскивать время, чтоб следовать советам и избегать антипаттернов. Так что если вы потратите время на то, чтоб следовать сиим шаблонам, это поможет для вас писать наиболее незапятнанные составляющие React. Я считаю эти шаблоны весьма полезными в моем проекте, и надеюсь, что вы тоже!

Создатель: Iskander Samatov

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Yandex.Дзен

Источник

Оценить статью
Блог о самом интересном.