Форум программистов, компьютерный форум, киберфорум
React/ReactJS
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/8: Рейтинг темы: голосов - 8, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 18.02.2021
Сообщений: 22

Пагинация API GitHub

22.05.2021, 16:47. Показов 1944. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Помогите с пагинацией с API GitHub.

App.js:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React from 'react';
import Pagination from './components/pagination';
import Info from './components/info';
import Reposit from './components/reposit';
class App extends React.Component {
  state = {
    repos: [],
    currentPage: 1;
  }
 
  gettingRepos = async (event) => {
    event.preventDefault();
    const person = event.target.elements.person.value;
    const arr = await fetch(`https://api.github.com/users/${person}/repos?per_page=10`);
    var reposits = await arr.json();
    this.setState({repos: reposits});
  };
 
 
  render() {
    return(
      <div>
        <Info reposMethod={this.gettingRepos}/>
        <Reposit repos={this.state.repos}/>
        <Pagination totalPosts={this.state.repos.length}/>
      </div>
    )
  }
};
export default App;
Info.js:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';
 
class Info extends React.Component{
render() {
  return (
    <div>
    <form onSubmit={this.props.reposMethod}>
      <input type="text" name="person"/>
      <button>Получить сведения</button>
    </form>
    </div>
  )
}
}
 
export default Info;
Reposit.js:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react';
 
class Reposit extends React.Component {
  render() {
    return(
      <div>
        {this.props.repos.map (repo => {
          return (
            <div>
              <p key={repo.full_name}>Имя репозитория: {repo.full_name}</p>
              <hr />
            </div>
          )
        })}
      </div>
    )
  }
}
 
export default Reposit;
Отдельный компонент для пагинации:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React from 'react';
 
const Pagination = ({ totalPosts, paginate }) => {
  const pageNumbers = [];
 
  for(let i = 1; i <= Math.ceil (totalPosts / 10); i++) {
    pageNumbers.push(i);
  }
 
  return (
    <div>
      <ul className="pagination">
        {pageNumbers.map(number => (
          <li key={number}>
            <a onClick={() => paginate(number)} href = "!#">
              {number}
            </a>
        </li>
        ))}
      </ul>
    </div>
  )
}
 
export default Pagination;
URL GitHub для пагинации: `https://api.github.com/users/${person}/repos?page=1&per_page=10`
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
22.05.2021, 16:47
Ответы с готовыми решениями:

API Github
Всем привет, подскажите библиотеки для работы(загрузка, удаление) файлов в репозитории. Ну, желательно бы и ссылку на статью, где есть...

GitHub API
Добрый день уважаемые форумчане, на протяжении многих лет черпал инфу с сего форума, и даже не нуждался в регистрации, так как искать...

Запрос к GitHub API
Всем привет! Решил сделать систему проверки обновлений для программы с GitHub. Для этого создаю HttpWebRequest и пытаюсь получить...

9
 Аватар для bodynar
345 / 307 / 135
Регистрация: 14.03.2015
Сообщений: 1,158
Записей в блоге: 1
22.05.2021, 18:27
AntonHPL, А в чем ваша проблема?

У вас есть API, которое предоставляет пагинацию.
В компоненте пагинации у вас есть номера страниц. По клику на номер страницы просто подставляете ее в url и запрашиваете данные.
0
0 / 0 / 0
Регистрация: 18.02.2021
Сообщений: 22
22.05.2021, 18:42  [ТС]
bodynar, как это записать?
0
 Аватар для bodynar
345 / 307 / 135
Регистрация: 14.03.2015
Сообщений: 1,158
Записей в блоге: 1
22.05.2021, 19:34
AntonHPL, Что именно записать?

Если у вас есть 3 компонента: Paginator, List, ListItem (названы условно), то все просто.

При инициализации List вы подгружаете количество страниц (на основании вашего числа эл. на странице) и первую страницу, которую рендерите в виде набора ListItem, а также рендерите Paginator, в который передаете конфигурацию из кол-ва страниц.

Далее в Paginator уже должна быть генерация страниц от 1 до последней с учетом текущей страницы. По действию нажатия на номер страницы вы должны загружать нужную страницу (как вы до этого загружали первую) и отображать по тому же алгоритму.
0
0 / 0 / 0
Регистрация: 18.02.2021
Сообщений: 22
22.05.2021, 19:53  [ТС]
bodynar, записать именно тот момент, когда мы нажимаем на кнопку, на цифру "N", выпадает именно N-ная страница.
0
 Аватар для bodynar
345 / 307 / 135
Регистрация: 14.03.2015
Сообщений: 1,158
Записей в блоге: 1
22.05.2021, 22:52
AntonHPL, Написал для вас простенький пример на codepen.

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
const mockItems = [
    { name: "Item 1" },
    { name: "Item 2" },
    { name: "Item 3" },
    { name: "Item 4" }
];
 
const loadData = (pageNum) => {
    return Promise.resolve(
        mockItems.map((x) => ({ ...x, name: `${x.name}. Page ${pageNum}` }))
    );
};
const getMetadata = () => {
    return Promise.resolve({ items: 100 });
};
 
const itemsOnPage = 10;
 
const ListItem = (props) => {
    return <span>{props.name}</span>;
};
 
const Paginator = (props) => {
    const pageNumbers = [...Array(props.pagesCount).keys()].map((a) => a + 1);
 
    const onPageNumberClick = React.useCallback(
        (event) => {
            const value = parseInt(event.target.innerHTML);
            if (!isNaN(value)) {
                props.onClick(value);
            }
        },
        [props]
    );
    return (
        <ul className="paginator" onClick={onPageNumberClick}>
            {pageNumbers.map((pageNumber) => (
                <li key={pageNumber}>{pageNumber}</li>
            ))}
        </ul>
    );
};
 
const App = () => {
    const [items, setItems] = React.useState([]);
    const [currentPage, setCurrentPage] = React.useState(0);
    const [pagesCount, setPagesCount] = React.useState(0);
 
    const onPageChange = React.useCallback(
        (pageNum) => {
            loadData(pageNum).then((x) => {
                setItems(x);
                setCurrentPage(pageNum);
            });
        },
        [setItems, setCurrentPage]
    );
 
    React.useEffect(() => {
        if (pagesCount === 0) {
            getMetadata().then((x) => {
                const pagesCount = x.items / itemsOnPage;
                setPagesCount(pagesCount);
            });
        }
 
        if (pagesCount !== 0 && items.length === 0) {
            onPageChange(0);
        }
    }, [pagesCount, onPageChange, setPagesCount, items, setItems]);
 
    return (
        <main>
            <div className="items">
                {items.map((item, i) => (
                    <ListItem key={i} name={item.name} />
                ))}
            </div>
            <Paginator
                currentPage={currentPage}
                pagesCount={pagesCount}
                onClick={onPageChange}
            />
        </main>
    );
};
 
ReactDOM.render(<App />, document.getElementById("root"));
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.items
    display: flex
    flex-direction: column
 
    span:not(:last-child)
        margin-bottom: 0.25rem
 
.paginator
    margin: 1em 0
    padding: 0
    list-style: none
    display: flex
    gap: 0.25rem
 
    li
        padding: 0.25rem
        cursor: pointer
        border: 1px solid gray
        border-radius: 4px
        background: rgba(0, 0, 0, 0.05)
 
        &:hover
            background: rgba(0, 0, 0, 0.15)
            border-color: blue
Здесь работа с API замокана через использование метода с Promise. Также нет возможности выбрать кол-во элементов на странице.
Но, думаю, вы сможете от этой основы оттолкнуться и доработать по требованиям
0
0 / 0 / 0
Регистрация: 18.02.2021
Сообщений: 22
23.05.2021, 10:07  [ТС]
bodynar, я полазил еще по просторам сети и скомпоновал вариант. Не могу сейчас увязать вывод репозиториев в зависимости от ввода имени пользователя. Надо по нажатии на кнопку формы выводить список репозиториев отдельного пользователя.
Подскажете, что там за строки надо добавить и куда?

App.js:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import React, { useState, useEffect } from 'react';
import Posts from './components/Posts';
import Pagination from './components/Pagination';
import Info from './components/Info'
import axios from 'axios';
import './App.css';
 
const App = () => {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(false);
  const [currentPage, setCurrentPage] = useState(1);
  const [postsPerPage] = useState(10);
 
  useEffect(() => {
    const fetchPosts = async (event) => {
      setLoading(true);
      const res = await axios.get(`https://api.github.com/users/bibeva/repos`);
      setPosts(res.data);
      setLoading(false);
    };
 
    fetchPosts();
  }, []);
 
  // Get current posts
  const indexOfLastPost = currentPage * postsPerPage;
  const indexOfFirstPost = indexOfLastPost - postsPerPage;
  const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost);
 
  // Change page
  const paginate = pageNumber => setCurrentPage(pageNumber);
 
  return (
    <div className='container mt-5'>
      <h1 className='text-primary mb-3'>My Blog</h1>
      <Info />
      <Posts posts={currentPosts} loading={loading} />
      <Pagination
        postsPerPage={postsPerPage}
        totalPosts={posts.length}
        paginate={paginate}
      />
    </div>
  );
};
 
export default App;
Info.js:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';
 
class Info extends React.Component{
render() {
  return (
    <div>
    <form onSubmit={this.props.reposMethod}>
      <input type="text" name="person"/>
      <button>Получить сведения</button>
    </form>
    </div>
  )
}
}
 
export default Info;
Posts.js:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from 'react';
 
const Posts = ({ posts, loading }) => {
  if (loading) {
    return <h2>Loading...</h2>;
  }
 
  return (
    <ul className='list-group mb-4'>
      {posts.map(post => (
        <li key={post.id} className='list-group-item'>
          {post.full_name}
        </li>
      ))}
    </ul>
  );
};
 
export default Posts;
Pagination.js:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React from 'react';
 
const Pagination = ({ postsPerPage, totalPosts, paginate }) => {
  const pageNumbers = [];
 
  for (let i = 1; i <= Math.ceil(totalPosts / postsPerPage); i++) {
    pageNumbers.push(i);
  }
 
  return (
    <nav>
      <ul className='pagination'>
        {pageNumbers.map(number => (
          <li key={number} className='page-item'>
            <a onClick={() => paginate(number)} href='!#' className='page-link'>
              {number}
            </a>
          </li>
        ))}
      </ul>
    </nav>
  );
};
 
export default Pagination;
0
 Аватар для bodynar
345 / 307 / 135
Регистрация: 14.03.2015
Сообщений: 1,158
Записей в блоге: 1
23.05.2021, 15:58
Цитата Сообщение от AntonHPL Посмотреть сообщение
https://api.github.com/users/bibeva/repos
Этот API возвращает все записи. Соответственно вам требуется пагинация на клиенте, верно?

Добавлено через 4 минуты
Цитата Сообщение от AntonHPL Посмотреть сообщение
JavaScript
1
2
// Change page
  const paginate = pageNumber => setCurrentPage(pageNumber);
У вас currentPage где-то фигурирует?

Если требуется пагинация на клиенте, то просто создайте новый массив для отображения (на замену текущему) и положите его под состояние (useState). При действии перехода на страницу делайте примерно следующее
JavaScript
1
2
const pageItems = allItems.slice(currentPage * itemsPerPage, (currentPage + 1) * itemsPerPage);
setPageItems(pageItems);
0
0 / 0 / 0
Регистрация: 18.02.2021
Сообщений: 22
23.05.2021, 20:29  [ТС]
bodynar, currentPage фигурирует при установлении первого и последнего постов (репозиториев) на конкретной страничке при пагинации.
Пользователь bibeva указан как пример.
В поле Input в компоненте Info мы должны ввести любого пользователя и нам выпадают все его репозитории. Я хотел в URL-запросе заковать в скобки эту переменную (person) и помещать в нее значение, введенное в Input. Но почему-то ошибка с event. Да и метод fetchPosts по сути должен вызываться при нажатии на кнопку формы в компоненте Info.

JavaScript
1
2
3
4
5
6
7
8
9
10
11
useEffect(() => {
    const fetchPosts = async (event) => {
      setLoading(true);
      const person = event.target.elemets.person.value; // Берем значение из поля в компоненте Info и подставляем в URL
      const res = await axios.get(`https://api.github.com/users/${person}/repos`);
      setPosts(res.data);
      setLoading(false);
    };
 
    fetchPosts(); // Он вызывается сразу в App.js, а надо, чтоб вызывался в Info при нажатии на кнопку формы.
  }, []);
0
 Аватар для bodynar
345 / 307 / 135
Регистрация: 14.03.2015
Сообщений: 1,158
Записей в блоге: 1
25.05.2021, 21:38
AntonHPL, Если я правильно понял вашу хотелку, то все также просто. Вот codepen

Это также основа, которую нужно доработать. После ввода в поле можно нажать на кнопку и запросить данные. Api замокан функцией с Promise.

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const mockItems = [
    { name: "Repository 1" },
    { name: "Repository 2" },
    { name: "Repository 3" },
    { name: "Repository 4" }
];
 
const loadRepositories = (userName) => {
    return Promise.resolve(mockItems);
};
 
const RepositoryList = (props) => {
    if (props.items.length === 0 || props.userName === "") {
        return <></>;
    }
    return (
        <div>
            <label>Repositories for {props.userName}</label>
            <ul className="items">
                {props.items.map((x) => (
                    <li key={x.name}>{x.name}</li>
                ))}
            </ul>
        </div>
    );
};
 
const App = () => {
    const [items, setItems] = React.useState([]);
    const [userName, setUserName] = React.useState("");
 
    const onShowRepositoriesClick = React.useCallback(() => {
        if (userName !== "") {
            loadRepositories(userName)
                .then((repositories) => setItems(repositories))
                .catch((x) => console.error(x));
        }
    }, [setItems, userName]);
 
    const onInputChange = React.useCallback(
        (event) => {
            const value = event.target.value;
 
            setUserName(value);
        },
        [setUserName]
    );
 
    return (
        <main>
            <div className="row">
                <label htmlFor="userName">Username:</label>
                <input type="text" name="userName" onChange={onInputChange} />
            </div>
            <div className="row">
                <button onClick={onShowRepositoriesClick}>Show repositories</button>
            </div>
            <hr />
            <RepositoryList userName={userName} items={items} />
        </main>
    );
};
 
ReactDOM.render(<App />, document.getElementById("root"));
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.items
    display: flex
    flex-direction: column
 
    span:not(:last-child)
        margin-bottom: 0.25rem
 
.row
    display: flex
    gap: 1rem
    margin-bottom: 0.5rem
 
button
    border: 1px solid rgb(0, 148, 148, 0.5)
    background-color: transparent
    padding: 0.25rem
    transition: 0.1s ease-in all
 
    &:hover
        background-color: rgb(0, 148, 148, 0.75)
        color: white
Добавлено через 6 минут
AntonHPL, В вашем коде:
- Объявление метода fetchPosts в контекте хука useEffect, что не позволяет вызвать вне хука
- fetchPosts вызывается при любом изменении компонента и возвращает одни и те же данные.

Вам нужно было просто вынести этот метод вне хука и вызывать по клику по кнопке, как в примере выше. Пример писал, не увидев ваш код
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
25.05.2021, 21:38
Помогаю со студенческими работами здесь

Парсер для API GitHub
Народ нужна помощь такого рода: Есть например страница GitHub-a с текстом: https://api.github.com/users/Gamblt 2 дня уже мучаюсь,...

Как обратится к API GitHub из программы С++
Я хочу сделать запрос https://api.github.com/users/Zhukovdpua/repos к API github из программы С++. Для работы с сетью использую winsock. ...

Как правильно использовать API github.com?
Как правильно использовать API github.com? Пробую получить информацию по токену с помощью запроса к API описанного по ссылке...

Работа с GitHub API в PHP, как сделать авторизацию ?
Суть задачи такая : пользователь авторизуется через OAuth2 в аккаунте GitHub и получает список своих репозиториев. Как сделать это на PHP +...

Сделать Fork репозитория через GitHub REST API v3
Задачка для видавших виды, форкнуть репозиторий гитхаба с помощью их же API, делаю такъ: const forkRepository = await...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru