maksipes
@maksipes

Делают ли так в React?

Продолжение вопроса - Делают ли так в Reacte?

Там меня убедили, что единый обработчик на все элементы Айтема не есть хорошо.

Решил сделать отдельные, это в общем-то даже удобнее, нежели возня в Селекте.

Но остается вопрос проброски ссылок на обработчики через Пропсы, когда их несколько - загромождает код.

Попробовал сделать так:

В Апп компоненте собираю все ссылки в объект и передаю его в вниз по иерархии.

<ItemsList items={items} handlers={this.aBunchOfHandlers}/>

  get aBunchOfHandlers() {
    return { onTextClick: this.onTextClick, onHintClick: this.onHintClick, onExtaClick: this.onExtaClick };
  }


На месте, в Айтиме делаю так:

export default class Item extends React.Component {
  render() {
    const { item, index, handlers } = this.props;
    return (
      <div className="item">
        <div className="item-over">...</div>
        <div className="item-main">
          <div className="item-text" onClick={handlers.onTextClick.bind(this, index)}>...</div>
          <div className="item-hint"  onClick={handlers.onHintClick.bind(this, index)}>...</div>
          <div className="item-extra" onClick={handlers.onExtraClick.bind(this, index)}>...</div>
        </div>
      </div>
    );
  }
}


И опять же вопрос - нормально ли такое в Реакте?

И еще - что лучше тут - бинд или стрелочная функция?
  • Вопрос задан
  • 146 просмотров
Решения вопроса 2
rockon404
@rockon404 Куратор тега React
Frontend Developer
Так тоже лучше не делать. Такая конструкция и читается хуже и в нее трудней вносить изменения. Хандлеры лучше передавать явно.

Давайте лучше разберем более приближенный к реальности кейс:
const Comment = ({ comment, meta, author, postLike, me }) => {
  const [shouldShowReply, setReply] = useState(false);

  const toggleReply = useCallback(() => {
    setReply(s => !s);
  }, []);

  const handleLikeClick = useCallback(() => {
    postLike(comment.id, me.id);
  }, []);

  const isLiked = useMemo(
    () => meta.likes.some(like => like.user_id === me.id),
    [meta.likes],
  );  

  return (
    <Wrapper>
      <Avatar src={user.avatar} to={`/users/${user.slug}`} />
      <CommentBody text={comment.body} />
      <Icon name="like" isActive={isLiked} onClick={handleLikeClick} />
      <Button type="link" onClick={toggleReply}>Reply</Button>
      {shouldShowReply && <ReplyForm />}
    <Wrapper/>
  );
}

const mapStateToProps = (state, ownProps) => ({
  me: meSelector(state),
  author: commentAuthorSelector(state, ownProps),
  meta: commentMetaSelector(state, ownProps),
});

const mapDispatchToProps = {
  postLike,
};

export default connect(mapStateToProps, mapDispatchToProps)(Comment);


Смотрите, что у нас получается, наш комментарий обрабатывает клик по аватару и клики по кнопкам Like и Reply.
Клик по аватару обрабатывается ссылкой роутера, а благодаря композиции реализация от нас скрыта и мы просто знаем, что в аватар достаточно передать src картинки и ссылку.
Клик по лайку обрабатывается асинхронной функцией действием, которая подключается с помощью HOC connect.
Клик по Reply обрабатывается внутренним хандлером компонента и изменяет его состояние.
На выходе мы имеем интерфейс для комментария подключенного к хранилищу следующего вида:
<Comment comment={comment} />
Для не подключенного:
<Comment
  me={me}
  author={author}
  meta={commentMeta}
  postLike={postLike}
  comment={comment}
/>

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

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

И еще - что лучше тут - бинд или стрелочная функция?

Это есть в документации.
Ответ написан
Комментировать
@lnked
class App extends React.Component {

  onTextClick = index => (e) => {
    ...
  }

  onHintClick = index => (e) => {
    ...
  }

  onExtaClick = index => (e) => {
    ...
  }

  render() {
    const items = [{}, {}];

    return (
      <ItemsList
        items={items}
        onTextClick={this.onTextClick}
        onHintClick={this.onHintClick}
        onExtaClick={this.onExtaClick}
      />
    )
  }
}

Item:
export default class Item extends React.Component {
  render() {
    const { item, index, onTextClick, onHintClick, onExtaClick } = this.props;

    return (
      <div className="item">
        <div className="item-over">...</div>
        <div className="item-main">
          <div className="item-text" onClick={onTextClick(index)} />
          <div className="item-hint"  onClick={onHintClick(index)} />
          <div className="item-extra" onClick={onExtraClick(index)} />
        </div>
      </div>
    );
  }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы