React-admin component does not use dataprovider to

2019-08-09 03:47发布

问题:

I want to add a custom Card onto one of my pages, which should call the rest api with filters.

I wrote a new component for that, but i got error return, that response is not defined. I checked, no calls are reaching my api, so i'm pretty sure response is not defined because the api call is not happening, not executing.

here's my component's code:

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.log(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; 

I want to use it in my List like this:

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>
);

and of course I have my App.js recourse for 'clicks' api call:

my App.js:

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

What do I do wrong that my datapovider does not call my api?

my dataprovider/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)
    );
};
};

回答1:

I could fix it in the meantime. There were multiple minor issues:

  • in List view my ClickStats were not working
    • DevTools showed it clearly
  • I had to change my dataprovider from ra-data-json-server to ra-data-simple-rest and suddenly everything was working


回答2:

First you need to initial your state

state = {
dailyclick : {}
};

then

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 }))
        }
    );
}