codesandbox.io
I'm trying to create a nice admin dashboard with react-admin
.
As using spring
in my backend and this is how am sending data to react-admin
:
@GetMapping("admin/user")
ResponseEntity<List<User>> getAll()
{
System.out.println(new Date());;
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("Content-Range", "posts 0-"+userRepository.findAll().size() + "/" + userRepository.findAll().size());
responseHeaders.set("Origin", "http://localhost:3001");
return ResponseEntity.ok()
.headers(responseHeaders)
.body(userRepository.findAll());
}
First of all this is not working and secondly, this is not even close to correct solution.
Unfortunately, my client renders the last thing over and over again.
As you can see below, element with id 129
is rendered over and over again!
At the frontend, within react.js
:
// Within main/parent component
class App extends Component {
render() {
return (
<Admin dataProvider={restProvider('http://localhost:8080/admin')}>
<Resource name="user" list={UserList}/>
</Admin>
);
}
};
// child component
const UserList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="userID" />
<TextField source="username" />
<TextField source="firstName" />
<TextField source="middleName" />
<TextField source="lastName" />
<TextField source="profileImageURL" />
<DateField source="joiningTime" />
<EditButton basePath="/posts" />
</Datagrid>
</List>
);
I think I need a method that sort of configures every controller response with a Content-Range
header.
Please note that my returned data works fine in postman
:
The never-ending challenge of consuming data from an API
Whatever is said in the answer above is true!
Based on the asked question, how do you provide an id
field for <Datagrid>
to iterate over your data and render each row/element uniquely?
Note that the React-Admin
dataProvider
often returns a response with a jsonObject {count: <Number>, results: <Array>}
. And the results array is often mapped onto the data key e.g.data: json.results
Here's what helped me while I used react-admin with a python/django backend
.
I believe in most cases, regardless of the backend, it's crucial to understand how react-admin
consumes data (in this case a list
). Two Solutions are possible:
If you have control over your backend (API), just like here.
Then kindly update/refactor your unique identifier (in this case, userID
) to be mapped/returned as just a plain id
field. This will make it easier for any client consuming your data using react-admin
or react.js
generally.
Ok, so you have no control over that backend (API)!
Then you'll have to use this line //data: json.map(record => ({"id": record.userID, ...record}))
.
Not too fast with solution two!
There lies the commonest pitfall when working with APIs.
While we fetch data, our client initially (the array/list, in this case json.results
) is undefined.
So javascript
will complain that it cannot read property 'map' of undefined
.
How do I solve such a challenge of undefined
?
Either directly initiate your data as an array
or instruct the map()
to only run if your data is not undefined (by including such a check, typeof json !== ‘undefined’
).
Try it here:
https://codesandbox.io/s/react-admin-sample-l692r
Each record must have a field named id
which in your case represents your userID
field.
Use users
for the resource name instead of user
.
If you cannot change that server side, you can do it in javascript.
The following sample code should work.
Add it to AdminPanel.js
file in your setup:
With your backend, uncomment the following lines:
//data: json.map(record => ({"id": record.userID, ...record})),
//total: parseInt(headers.get('content-range').split('/').pop(), 10),
And change the following line:
const apiUrl = "https://jsonplaceholder.typicode.com";
to
const apiUrl = "http://localhost:8080/admin";
import React from "react";
import { Admin, Resource, fetchUtils } from "react-admin";
import restProvider from "ra-data-simple-rest";
import { UserList, LoginCredentialList } from "./posts";
import { stringify } from "query-string";
const apiUrl = "https://jsonplaceholder.typicode.com";
const httpClient = fetchUtils.fetchJson;
const myDataProvider = {
...restProvider,
getList: (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify(params.filter)
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ headers, json }) => ({
data: json,
//data: json.map(record => ({"id": record.userID, ...record})),
total: 10, //temporary hardcoded to avoid headers error.
//total: parseInt(headers.get('content-range').split('/').pop(), 10),
}));
}
};
class AdminPanel extends React.Component {
render() {
return (
<div>
<Admin dataProvider={myDataProvider}>
<Resource name="users" list={UserList} />
<Resource name="loginCredential" list={LoginCredentialList} />
</Admin>
</div>
);
}
}
export default AdminPanel;
// <Resource name="posts" list={UserList} edit={PostEdit} create={PostCreate}/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With