Возможно ли написать универсальный компонент? (react / typescript)

#javascript #reactjs #typescript

#javascript #reactjs #typescript

Вопрос:

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

 obj1 {id: 1, textVar: 'textString1', titleVar: 'titleString1', date1: '2000-10-10'}

obj2 {id: 2, title2: 'titleString2', someDate: '2001-11-11', otherTextVar: 'textString2'}

obj3 {id: 3, otherText3: 'textString3', otherDate: '2000-10-10', newsTitle: 'titleString3'}
 

Возможно ли написать универсальный компонент, который может работать с любым из объектов?

 interface UCompProps {
    id: number,
    title: string,
    text: string,
    date: string,
  }, 
}

const UComponent: React.FC<UCompProps> = (props) => {
  const { id, title, text, date } = props;
  return (
    <>
      <div>{id}</div>
      <div>{title}</div>
      <div>{text}</div>
      <div>{date}</div>
    </>
  )
}

export default UCompProps
 

Понятия не имею, как это сделать. Любой совет, как это сделать?

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

1. Да, вы могли бы использовать Object.entries для реквизитов, но мне это не кажется правильным.. Приведенный выше код с таким же успехом может означать, что вы только что отправили массив или объект в 1 prop.

2. Если порядок идентификаторов, заголовка, текста, даты одинаковы, вы можете легко использовать Object.values()

3. Нет, у него не тот же порядок. вся проблема в том, что я не могу знать, что есть что. Заголовок и текст — это строки, и они могут иметь любые ключевые имена: (

4. Есть ли шанс, что вы можете контролировать, как генерируются входные модули?

5. Серверная часть написана другими людьми, и есть некоторые очень похожие данные. Мне нужно создать компонент, который выводит предварительный просмотр для этих данных. (например: список новостей, список статей, список продаж и другие.)

Ответ №1:

Если вы знаете структуры всех объектов, то вы можете сопоставить массив этих объектов.

 // in parent:
return (
  <div>
    {arrayOfobjects1
      .map(obj1=>({
        id:obj1.id, title:obj1.titleVar , text:obj1.textVar, date: obj1.date1
      }))
      .map(props=><Ucomponent key={props.id} {...props} />)
    }
  </div>
)
 

А также вы можете определить, что функции отображения для каждого типа объектов:

 // in parent:

const mapper1 = object1 => ({id:obj1.id, title:obj1.titleVar, text:obj1.textVar, date: obj1.date1});

return (
  <div>
    {arrayOfobjects1
      .map(mapper1)
      .map(props=><Ucomponent key={props.id} {...props} />)
    }
  </div>
)
 

Или вы можете отобразить их все вместе после сопоставления каждого массива

 const arrayToRender = [...arr1.map(mapper1), ...arr2.map(mapper2), ...arr3.map(mapper3)];
 

Ответ №2:

Если порядок идентификаторов, заголовка, текста, даты одинаковы, вы можете легко использовать Object.values()

 const UComponent = (props) => {
  const { id, title, text, date } = props;
  
  return (
    <div>
      <div>ID: {id}</div>
      <div>TITLE: {title}</div>
      <div>TEXT: {text}</div>
      <div>DATE: {date}</div>
      <br/>
    </div>
  )
}

const App = (props) => {
  const { data } = props;

  const components = data.map((obj) => {
    const [id, title, text, date] = Object.values(obj);
    return <UComponent id={id} title={title} text={text} date={date} />;
  });

  return (
    <div>
      {components}
    </div>
  )
}

const objs = [
  {id: 1, titleVar: 'titleString1', date1: '2000-10-10', textVar: 'textString1'},
  {id: 2, title2: 'titleString2', someDate: '2001-11-11', otherTextVar: 'textString2'},
  {id: 3, newsTitle: 'titleString3', otherDate: '2000-10-10', otherText3: 'textString3'},
];

ReactDOM.render(
  <App data={objs} />,
  document.getElementById("react")
); 
 <div id="react"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>