gpt4 book ai didi

react-admin 如何创建客户端列表 Controller

转载 作者:行者123 更新时间:2023-12-04 15:55:23 26 4
gpt4 key购买 nike

你知道如何创建客户端列表 Controller 吗?

我检查了 StackOverflow - 我没有找到问题的答案。

有没有一种简单的方法来创建一个资源,该资源在第一页加载时从服务器读取所有记录。然后排序,过滤,分页在客户端完成。还可以选择禁用分页。

我试图从 ra-core 复制 ListController.js 和从 ra-ui-materialui 复制 List.js 并自定义它,但是错误,我可以前进。我不熟悉 react 和制作 PoC。

这里是错误:

TypeError: Cannot read property 'apply' of undefined
(anonymous function)
node_modules/recompose/compose.js:22
19 |
20 | return funcs.reduce(function (a, b) {
21 | return function () {
22 | return a(b.apply(undefined, arguments));
23 | };
24 | });
25 | }
View compiled
./src/ListController.js
src/ListController.js:431
428 | export default compose(
429 | connect(
430 | mapStateToProps,
431 | {
432 | crudGetList: crudGetListAction,
433 | changeListParams: changeListParamsAction,
434 | setSelectedIds: setListSelectedIdsAction,
View compiled

我已经将导入从相对路径更改为导入react-admin;关于如何修复错误的任何建议?

这是更改后的 ListController.js 文件:

/* eslint no-console: ["error", { allow: ["warn", "error"] }] */
import { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { parse, stringify } from 'query-string';
import { push as pushAction } from 'react-router-redux';
import compose from 'recompose/compose';
import { createSelector } from 'reselect';
import inflection from 'inflection';
import debounce from 'lodash/debounce';
import isEqual from 'lodash/isEqual';
import pickBy from 'lodash/pickBy';

import removeEmpty from 'react-admin';
import queryReducer, {
SET_SORT,
SET_PAGE,
SET_PER_PAGE,
SET_FILTER,
SORT_DESC,
} from 'react-admin';
import { crudGetList as crudGetListAction } from 'react-admin';
import {
changeListParams as changeListParamsAction,
setListSelectedIds as setListSelectedIdsAction,
toggleListItem as toggleListItemAction,
} from 'react-admin';
import translate from 'react-admin';
import removeKey from 'react-admin';

/**
* List page component
*
* The <List> component renders the list layout (title, buttons, filters, pagination),
* and fetches the list of records from the REST API.
* It then delegates the rendering of the list of records to its child component.
* Usually, it's a <Datagrid>, responsible for displaying a table with one row for each post.
*
* In Redux terms, <List> is a connected component, and <Datagrid> is a dumb component.
*
* Props:
* - title
* - perPage
* - sort
* - filter (the permanent filter to apply to the query)
* - actions
* - filters (a React Element used to display the filter form)
* - pagination
*
* @example
* const PostFilter = (props) => (
* <Filter {...props}>
* <TextInput label="Search" source="q" alwaysOn />
* <TextInput label="Title" source="title" />
* </Filter>
* );
* export const PostList = (props) => (
* <List {...props}
* title="List of posts"
* sort={{ field: 'published_at' }}
* filter={{ is_published: true }}
* filters={<PostFilter />}
* >
* <Datagrid>
* <TextField source="id" />
* <TextField source="title" />
* <EditButton />
* </Datagrid>
* </List>
* );
*/
export class ListController extends Component {
state = {};

componentDidMount() {
if (
!this.props.query.page &&
!(this.props.ids || []).length &&
this.props.params.page > 1 &&
this.props.total > 0
) {
this.setPage(this.props.params.page - 1);
return;
}

this.updateData();
if (Object.keys(this.props.query).length > 0) {
this.props.changeListParams(this.props.resource, this.props.query);
}
}

componentWillUnmount() {
this.setFilters.cancel();
}

componentWillReceiveProps(nextProps) {
if (
nextProps.resource !== this.props.resource ||
nextProps.query.sort !== this.props.query.sort ||
nextProps.query.order !== this.props.query.order ||
nextProps.query.page !== this.props.query.page ||
nextProps.query.filter !== this.props.query.filter
) {
this.updateData(
Object.keys(nextProps.query).length > 0
? nextProps.query
: nextProps.params
);
}
if (nextProps.version !== this.props.version) {
this.updateData();
}
}

shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.translate === this.props.translate &&
nextProps.isLoading === this.props.isLoading &&
nextProps.version === this.props.version &&
nextState === this.state &&
nextProps.data === this.props.data &&
nextProps.selectedIds === this.props.selectedIds &&
nextProps.total === this.props.total
) {
return false;
}
return true;
}

/**
* Merge list params from 4 different sources:
* - the query string
* - the params stored in the state (from previous navigation)
* - the filter defaultValues
* - the props passed to the List component
*/
getQuery() {
const query =
Object.keys(this.props.query).length > 0
? this.props.query
: { ...this.props.params };
const filterDefaultValues = this.props.filterDefaultValues || {};

query.filter = { ...filterDefaultValues, ...query.filter };

if (!query.sort) {
query.sort = this.props.sort.field;
query.order = this.props.sort.order;
}
if (!query.perPage) {
query.perPage = this.props.perPage;
}
if (!query.page) {
query.page = 1;
}
return query;
}

updateData(query) {
const params = query || this.getQuery();
const { sort, order, page = 1, perPage, filter } = params;
const pagination = {
page: parseInt(page, 10),
perPage: parseInt(perPage, 10),
};
const permanentFilter = this.props.filter;
this.props.crudGetList(
this.props.resource,
pagination,
{ field: sort, order },
{ ...filter, ...permanentFilter }
);
}

setSort = sort => this.changeParams({ type: SET_SORT, payload: sort });

setPage = page => this.changeParams({ type: SET_PAGE, payload: page });

setPerPage = perPage =>
this.changeParams({ type: SET_PER_PAGE, payload: perPage });

setFilters = debounce(filters => {
if (isEqual(filters, this.props.filterValues)) {
return;
}

// fix for redux-form bug with onChange and enableReinitialize
const filtersWithoutEmpty = removeEmpty(filters);
this.changeParams({ type: SET_FILTER, payload: filtersWithoutEmpty });
}, this.props.debounce);

showFilter = (filterName, defaultValue) => {
this.setState({ [filterName]: true });
if (typeof defaultValue !== 'undefined') {
this.setFilters({
...this.props.filterValues,
[filterName]: defaultValue,
});
}
};

hideFilter = filterName => {
this.setState({ [filterName]: false });
const newFilters = removeKey(this.props.filterValues, filterName);
this.setFilters(newFilters);
};

handleSelect = ids => {
this.props.setSelectedIds(this.props.resource, ids);
};

handleUnselectItems = () => {
this.props.setSelectedIds(this.props.resource, []);
};

handleToggleItem = id => {
this.props.toggleItem(this.props.resource, id);
};

changeParams(action) {
const newParams = queryReducer(this.getQuery(), action);
this.props.push({
...this.props.location,
search: `?${stringify({
...newParams,
filter: JSON.stringify(newParams.filter),
})}`,
});
this.props.changeListParams(this.props.resource, newParams);
}

render() {
const {
basePath,
children,
resource,
hasCreate,
data,
ids,
total,
isLoading,
translate,
version,
selectedIds,
} = this.props;
const query = this.getQuery();

const queryFilterValues = query.filter || {};

const resourceName = translate(`resources.${resource}.name`, {
smart_count: 2,
_: inflection.humanize(inflection.pluralize(resource)),
});
const defaultTitle = translate('ra.page.list', {
name: `${resourceName}`,
});

return children({
basePath,
currentSort: {
field: query.sort,
order: query.order,
},
data,
defaultTitle,
displayedFilters: this.state,
filterValues: queryFilterValues,
hasCreate,
hideFilter: this.hideFilter,
ids,
isLoading,
onSelect: this.handleSelect,
onToggleItem: this.handleToggleItem,
onUnselectItems: this.handleUnselectItems,
page: parseInt(query.page || 1, 10),
perPage: parseInt(query.perPage, 10),
refresh: this.refresh,
resource,
selectedIds,
setFilters: this.setFilters,
setPage: this.setPage,
setPerPage: this.setPerPage,
setSort: this.setSort,
showFilter: this.showFilter,
translate,
total,
version,
});
}
}

ListController.propTypes = {
// the props you can change
children: PropTypes.func.isRequired,
filter: PropTypes.object,
filters: PropTypes.element,
filterDefaultValues: PropTypes.object, // eslint-disable-line react/forbid-prop-types
pagination: PropTypes.element,
perPage: PropTypes.number.isRequired,
sort: PropTypes.shape({
field: PropTypes.string,
order: PropTypes.string,
}),
// the props managed by react-admin
authProvider: PropTypes.func,
basePath: PropTypes.string.isRequired,
changeListParams: PropTypes.func.isRequired,
crudGetList: PropTypes.func.isRequired,
data: PropTypes.object, // eslint-disable-line react/forbid-prop-types
debounce: PropTypes.number,
filterValues: PropTypes.object, // eslint-disable-line react/forbid-prop-types
hasCreate: PropTypes.bool.isRequired,
hasEdit: PropTypes.bool.isRequired,
hasList: PropTypes.bool.isRequired,
hasShow: PropTypes.bool.isRequired,
ids: PropTypes.array,
selectedIds: PropTypes.array,
isLoading: PropTypes.bool.isRequired,
location: PropTypes.object.isRequired,
path: PropTypes.string,
params: PropTypes.object.isRequired,
push: PropTypes.func.isRequired,
query: PropTypes.object.isRequired,
resource: PropTypes.string.isRequired,
setSelectedIds: PropTypes.func.isRequired,
toggleItem: PropTypes.func.isRequired,
total: PropTypes.number.isRequired,
translate: PropTypes.func.isRequired,
version: PropTypes.number,
};

ListController.defaultProps = {
debounce: 500,
filter: {},
filterValues: {},
perPage: 10,
sort: {
field: 'id',
order: SORT_DESC,
},
};

const injectedProps = [
'basePath',
'currentSort',
'data',
'defaultTitle',
'displayedFilters',
'filterValues',
'hasCreate',
'hideFilter',
'ids',
'isLoading',
'onSelect',
'onToggleItem',
'onUnselectItems',
'page',
'perPage',
'refresh',
'resource',
'selectedIds',
'setFilters',
'setPage',
'setPerPage',
'setSort',
'showFilter',
'total',
'translate',
'version',
];

/**
* Select the props injected by the ListController
* to be passed to the List children need
* This is an implementation of pick()
*/
export const getListControllerProps = props =>
injectedProps.reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});

/**
* Select the props not injected by the ListController
* to be used inside the List children to sanitize props injected by List
* This is an implementation of omit()
*/
export const sanitizeListRestProps = props =>
Object.keys(props)
.filter(props => !injectedProps.includes(props))
.reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});

const validQueryParams = ['page', 'perPage', 'sort', 'order', 'filter'];
const getLocationPath = props => props.location.pathname;
const getLocationSearch = props => props.location.search;
const selectQuery = createSelector(
getLocationPath,
getLocationSearch,
(path, search) => {
const query = pickBy(
parse(search),
(v, k) => validQueryParams.indexOf(k) !== -1
);
if (query.filter && typeof query.filter === 'string') {
try {
query.filter = JSON.parse(query.filter);
} catch (err) {
delete query.filter;
}
}
return query;
}
);

function mapStateToProps(state, props) {
const resourceState = state.admin.resources[props.resource];

return {
query: selectQuery(props),
params: resourceState.list.params,
ids: resourceState.list.ids,
selectedIds: resourceState.list.selectedIds,
total: resourceState.list.total,
data: resourceState.data,
isLoading: state.admin.loading > 0,
filterValues: resourceState.list.params.filter,
version: state.admin.ui.viewVersion,
};
}

export default compose(
connect(
mapStateToProps,
{
crudGetList: crudGetListAction,
changeListParams: changeListParamsAction,
setSelectedIds: setListSelectedIdsAction,
toggleItem: toggleListItemAction,
push: pushAction,
}
),
translate
)(ListController);

最佳答案

用自定义 dataProvider 处理这个用例会更容易.

每次您在 ListView 中执行操作(排序、过滤等)时,React Admin 都会向数据提供者询问数据。

例如,假设我们要列出用户,然后按性别筛选,然后按年龄排序。将使用以下参数调用数据提供程序三次:

dataProvider('GET_LIST', 'user', { sort: defaultSort, filters: defaultFilters });
dataProvider('GET_LIST', 'user', { sort: defaultSort, filters: { gender: 'm' } });
dataProvider('GET_LIST', 'user', { sort: { field: 'age', order: 'DESC' }, filters: { gender: 'm' } });

因此,为了实现您想要的行为,您的自定义数据提供程序应该是这样的:

// customDataResolver.js
import simpleRestProvider from 'ra-data-simple-rest';

const restDataProvider = simpleRestDataProvider('http://example.com/api');

let users; // In-memory cache (but you can write in storage or something)

export default (type, resource, params) => {
if (type === 'GET_LIST' && resource === 'users') {
if (!users) {
return restDataProvider(type, resource, params)
.then((data) => {
users = data;
return data;
});
}

return users
.sort(sortBy(params.sort))
.filter(filterBy(params.filter));
};

return restDataProvider(type, resource, params);
};

关于react-admin 如何创建客户端列表 Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51929058/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com