Компонент React-admin не использует поставщика данных для вызова API

Я хочу добавить пользовательскую карту на одну из моих страниц, которая должна вызывать остальные API с фильтрами.

Я написал для этого новый компонент, но получил сообщение об ошибке, этот ответ не определен. Я проверил, к моему API не поступают вызовы, поэтому я почти уверен, что ответ не определен, потому что вызов API не происходит, не выполняется.

вот код моего компонента:

import React, { Component } from 'react';
import { GET_LIST } from 'react-admin';
import dataProviderFactory from '../dataprovider/rest';

import StatsCard from './from_director/StatsCard';


class ClickStats extends Component {
    state = {};

componentDidMount() {
    dataProviderFactory(process.env.REACT_APP_DATA_PROVIDER).then(
        dataProvider => {
            dataProvider(GET_LIST, 'clicks', {
                filter: {
                    interval: 'day',
                    site_id: '1',
                    count: '1'
                },
            })
                .then(response => response.data)
                .then( dailyclick =>
                    this.setState({ dailyclick: response.data }),
                    console.info(response.data)
                )
        }
    );
}

render() {
    const {
        dailyclick,
    } = this.state;
    return (
                <StatsCard
                  statValue = {dailyclick}
                  statLabel = {'Napi Katt'}
                  icon = {<i className = "fa fa-check-square-o"></i>}
                  backColor = {'red'}
                />
    );
}
}
export default ClickStats; 

Я хочу использовать его в своем списке следующим образом:

import ClickStats from '../field/ClickStats';

export const ClickList = props => (
    <List {...props} bulkActions = {false} filters = {<ClickFilterList />} pagination = {<ClickPagination />} perPage = {20000}>
        <ClickStats />
        <Datagrid rowClick = "edit">
            <ReferenceField label = "Hirdeto" source = "ad" reference = "ads" linkType = {false}><NumberField label = "Hirdeto" source = "users.name" /></ReferenceField>
            <ReferenceField label = "Hirdetes" source = "ad" reference = "ads"><NumberField label = "Hirdetes" source = "title" /></ReferenceField>
            <IpConverter source = "ip" />
            <TextField source = "time" />
        </Datagrid>
    </List>
);

и, конечно же, у меня есть мой ресурс App.js для вызова API «кликов»:

мой App.js:

<Resource name = "clicks" options = {{ label: 'Legutóbbi kattintások' }} list = {ClickList} />

Что я делаю не так, что мой datapovider не вызывает мой API?

мой поставщик данных /rest.js

import { stringify } from 'query-string';
import {
  fetchUtils,
  GET_LIST,
  GET_ONE,
  GET_MANY,
  GET_MANY_REFERENCE,
  CREATE,
  UPDATE,
  UPDATE_MANY,
  DELETE,
  DELETE_MANY,
} from 'react-admin';

export default (apiUrl, httpClient = fetchUtils.fetchJson) => {
const convertDataRequestToHTTP = (type, resource, params) => {
    let url = '';
    const options = {};
    switch (type) {
        case GET_LIST: {
            const { page, perPage } = params.pagination;
            const { field, order } = params.sort;
            const query = {
                ...fetchUtils.flattenObject(params.filter),
                sort: field,
                order: order,
                start: (page - 1) * perPage,
                end: page * perPage,
            };
                url = `${apiUrl}/${resource}?${stringify(query)}`;
            break;
        }
        case GET_ONE:
            url = `${apiUrl}/${resource}/${params.id}`;
            break;
        case GET_MANY_REFERENCE: {
            const { page, perPage } = params.pagination;
            const { field, order } = params.sort;
            const query = {
                ...fetchUtils.flattenObject(params.filter),
                [params.target]: params.id,
                _sort: field,
                _order: order,
                _start: (page - 1) * perPage,
                _end: page * perPage,
            };
            url = `${apiUrl}/${resource}?${stringify(query)}`;
            break;
        }
        case UPDATE:
            url = `${apiUrl}/${resource}/${params.id}`;
            options.method = 'POST';
            options.body = JSON.stringify(params.data);
            break;
        case CREATE:
            url = `${apiUrl}/${resource}`;
            options.method = 'PUT';
            options.body = JSON.stringify(params.data);
            break;
        case DELETE:
            url = `${apiUrl}/${resource}/${params.id}`;
            options.method = 'DELETE';
            break;
        case GET_MANY: {
            url = `${apiUrl}/${resource}`;
            break;
        }
        default:
            throw new Error(`Unsupported fetch action type ${type}`);
    }
    return { url, options };
};

const convertHTTPResponse = (response, type, resource, params) => {
    const { headers, json } = response;
    switch (type) {
        case GET_LIST:
        case GET_MANY_REFERENCE:
            if (!headers.has('x-total-count')) {
                throw new Error(
                    'The X-Total-Count header is missing in the HTTP Response. The jsonServer Data Provider expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers header?'
                );
            }
            return {
                data: json,
                total: parseInt(
                    headers
                        .get('x-total-count')
                        .split('/')
                        .pop(),
                    10
                ),
            };
        case CREATE:
            return { data: { ...params.data, id: json.id } };
        default:
            return { data: json };
    }
};

return (type, resource, params) => {
    // json-server doesn't handle filters on UPDATE route, so we fallback to calling UPDATE n times instead
    if (type === UPDATE_MANY) {
        return Promise.all(
            params.ids.map(id =>
                httpClient(`${apiUrl}/${resource}/${id}`, {
                    method: 'PUT',
                    body: JSON.stringify(params.data),
                })
            )
        ).then(responses => ({
            data: responses.map(response => response.json),
        }));
    }
    // json-server doesn't handle filters on DELETE route, so we fallback to calling DELETE n times instead
    if (type === DELETE_MANY) {
        return Promise.all(
            params.ids.map(id =>
                httpClient(`${apiUrl}/${resource}/${id}`, {
                    method: 'DELETE',
                })
            )
        ).then(responses => ({
            data: responses.map(response => response.json),
        }));
    }
    const { url, options } = convertDataRequestToHTTP(
        type,
        resource,
        params
    );
    return httpClient(url, options).then(response =>
        convertHTTPResponse(response, type, resource, params)
    );
};
};

Итак, вы тщательно его отладили, добавили console.info() в разные места вызова dataProviderFactory из вашего компонента, что-нибудь появилось, что могло бы помочь? В первом .then() как выглядит «ответ»?

rrd 28.02.2019 16:06

Ответ: undef... и, как я уже сказал, API ничего не передает... Где react-admin извлекает данные с помощью данного вызова dataProvider? Насколько я понимаю, dataProviderFactory просто создает объект, но не извлекает его. Как это работает в реакции?

Reka Karolyi 28.02.2019 16:37
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
2
3 162
2

Ответы 2

Сначала вам нужно инициализировать свое состояние

state = {
dailyclick : {}
};

тогда

componentDidMount() {
    dataProviderFactory(process.env.REACT_APP_DATA_PROVIDER).then(
        dataProvider => {
            dataProvider(GET_LIST, 'clicks', {
                filter: {
                    interval: 'day',
                    site_id: '1',
                    count: '1'
                },
            })
                .then(response => this.setState({ dailyclick: response.data }))
        }
    );
}

Я сделал это, фиксированное состояние, но я все еще получаю undef для dailyclick. Я должен вернуть JSON с 1 элементом из API, что-то вроде этого: {count: 0}, поэтому я просто установил this.setState({ dailyclick: response.data.count }) - на этот раз я получил undef: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Также я не вижу в логах входящий вызов API на стороне API.

Reka Karolyi 28.02.2019 16:31

Я мог бы исправить это в то же время. Было несколько мелких проблем:

  • в представлении списка мои ClickStats не работали
    • DevTools наглядно показал это
  • Мне пришлось сменить поставщика данных с ra-data-json-server на ra-data-simple-rest, и вдруг все заработало.

Другие вопросы по теме