Обратный вызов JSX без передачи отдельных реквизитов

#javascript #reactjs #typescript #callback #jsx

#javascript #reactjs #typescript #обратный вызов #jsx

Вопрос:

Интересно, есть ли способ повторить такое же использование обратного вызова js в JSX, например:

 [1,2,3].map(console.log) // Here map iterator takes care of passing values to iteratee.
 

Есть ли аналогичный способ передачи подобного компонента, т.Е.. вместо этого:

 <List data={data} renderItem={item => <Post {...item} />} />
 

что-то вроде этого:

 <List data={data} renderItem={<Post/>} />
 

Комментарии:

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

Ответ №1:

Ах, хорошо, только что узнал, что вы можете использовать компоненты как простые функции js:

  <List data={data} renderItem={Post} />
 

Ответ №2:

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

Например, если вы хотите сделать что-то столь же простое, как рендеринг спонсируемого Post , код становится излишне сложным:

 // Index.js
<List data={data} renderItem={Post} renderSponsoredItem={SponsoredPost} />
 
 // List.js
function List({ data, renderItem, renderSponsoredItem }) {
  <div className={styles.list}>
    data.map(dataItem => {
      if (dataItem.sponsored) {
        return renderSponsoredItem(dataItem);
      } else {
        return renderItem(dataItem);
      }
    });
  </div>
}
 

… и в некотором смысле это в конечном итоге выглядит совсем не так, как React, и не использует простоту использования и удобочитаемость, которые возможны с React.

Альтернатива может выглядеть примерно так:

 // Index.js
<List>
  {data.map(dataItem => {
    if (dataItem.sponsored) {
      return <SponsoredPost post={dataItem} />;
    } else {
      return <Post post={dataItem} />
    } 
  })
</List>
 
 // List.js
function List({ children }) {
  <div className={styles.list}>
    {children}
  </div>
}
 

Я обнаружил, что первая форма подходит для нечитаемого кода и неработоспособных, нечитаемых компонентов в долгосрочной перспективе, а последняя намного проще для чтения / работы.

Комментарии:

1. Спасибо за подробный ответ, но имхо, если мы посмотрим с уровня родительского компонента (в данном случае List), ему не нужно знать подробности о том, какой тип сообщения он должен отображать. В принципе, вы можете использовать условную логику в Post, чтобы определить, будет ли текущий элемент данных SponsoredPost или каким-либо другим типом Post. Кроме того, List на самом деле является компонентом из akveo.github.io/react-native-ui-kitten/docs/components/list /…

2. Как я уже сказал, вы можете пойти в этом направлении, но это почти всегда приводит к более запутанному коду и плохому дизайну компонентов. Вы, очевидно, ограничены кодом библиотеки, но IMO дизайн компонентов в этой библиотеке довольно плохой.