Обзор кода компонентов App.tsx и Post.tsx

Не храните выбранный post отдельным состоянием: вычисляйте его из selectedId. Добавьте key, типы props, alt и клавиатурно доступную кнопку вместо кликабельного div.

Короткий ответ

Что ответить на собеседовании

Не храните выбранный post отдельным состоянием: вычисляйте его из selectedId. Добавьте key, типы props, alt и клавиатурно доступную кнопку вместо кликабельного div.

Подробный разбор

Ответ с пояснениями

Условие

Необходимо выполнить ревью исходных файлов App.tsx и Post.tsx.

// App.tsx

import React, { useEffect, useState } from "react";
import "./index.css";
import PostComponent from "./Post";

export default function App() {
  const posts_list = [
    {
      id: "1",
      name: "siberia can code 📘",
      imagesrc: "https://avatars.githubusercontent.com/u/45297354?v=4",
      text: "first post"
    },
    {
      id: "2",
      name: "theo",
      imagesrc: "https://avatars.githubusercontent.com/u/6751787?v=4",
      text: "second post"
    },
    {
      id: "3",
      name: "dan abramov",
      imagesrc: "https://avatars.githubusercontent.com/u/810438?v=4",
      text: "third post"
    }
  ];

  const [selectedId, setPostId] = React.useState(0);
  const [post, setSelectedPost] = React.useState(posts_list[0]);
  console.log("@", selectedId);

  useEffect(() => {
    setSelectedPost(posts_list[selectedId]);
  }, [selectedId]);

  return (
    <div className="App">
      <div>выбранный пользователь:</div>
      <div className="user">
        <img
          className={"avatar"}
          src={post.imagesrc}
          style={{ width: "30px" }}
        />
        {post.name}
      </div>
      <br />
      <br />
      <br />
      <div>список постов</div>
      {posts_list.length
        ? posts_list.map((el, index) => (
            <PostComponent data={el} onClick={() => setPostId(index)} />
          ))
        : []}
    </div>
  );
}

// Post.tsx

const Posts = ({ data, onClick }: any) => {
  const IMAGE = data.imagesrc;

  return (
    <div className="post" onClick={onClick}>
      <img className={"avatar"} src={IMAGE} style={{ width: "30px" }} />
      {data.name}
      <p>{data.text}</p>
    </div>
  );
};

export default Posts;

Ответ

Не храните выбранный post отдельным состоянием: вычисляйте его из selectedId. Добавьте key, типы props, alt и клавиатурно доступную кнопку вместо кликабельного div.

Вынесите постоянный posts_list за App и храните реальный ID, а не индекс:

type Post = { id: string; name: string; imagesrc: string; text: string };
const [selectedId, setSelectedId] = useState(posts_list[0]?.id ?? null);
const post = posts_list.find(item => item.id === selectedId);
// В JSX:
{post && <div className="user">
  <img className="avatar" src={post.imagesrc} alt="" width={30} />{post.name}
</div>}
{posts_list.map(item => <PostComponent key={item.id} data={item}
  onClick={() => setSelectedId(item.id)} />)}

Post.tsx:

type Props = { data: Post; onClick: () => void };
export default function PostComponent({ data, onClick }: Props) {
  return <button type="button" className="post" onClick={onClick}>
    <img className="avatar" src={data.imagesrc} alt="" width={30} />
    <span>{data.name}</span><span>{data.text}</span>
  </button>;
}

Общий тип Post экспортируйте из файла типов. Удалите эффект синхронизации и лишние импорты. Для отступов используйте CSS вместо цепочки br. Защита post от undefined нужна при пустом или изменившемся списке.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее