Skip to content

Commit

Permalink
add useReferenceMany Hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
ThieryMichel committed May 20, 2019
1 parent 6da919f commit af98d09
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 114 deletions.
142 changes: 28 additions & 114 deletions packages/ra-core/src/controller/field/ReferenceManyFieldController.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import { ReactNode, useState, useReducer, useEffect, useMemo } from 'react';
// @ts-ignore
import { useSelector, useDispatch } from 'react-redux';
import get from 'lodash/get';
import { ReactElement, FunctionComponent } from 'react';

import { crudGetManyReference } from '../../actions';
import {
SORT_ASC,
SORT_DESC,
} from '../../reducer/admin/resource/list/queryReducer';
import {
getIds,
getReferences,
getTotal,
nameRelatedTo,
} from '../../reducer/admin/references/oneToMany';
import { Record, Sort, RecordMap, Identifier, Dispatch } from '../../types';
import useReferenceMany from './useReferenceMany';

interface ChildrenFuncParams {
currentSort: Sort;
Expand All @@ -32,11 +23,8 @@ interface ChildrenFuncParams {

interface Props {
basePath: string;
children: (params: ChildrenFuncParams) => ReactNode;
data?: RecordMap;
children: (params: ChildrenFuncParams) => ReactElement<ChildrenFuncParams>;
filter?: any;
ids?: any[];
loadedOnce?: boolean;
perPage?: number;
record?: Record;
reference: string;
Expand All @@ -58,8 +46,6 @@ const sortReducer = (state: Sort, field: string | Sort): Sort => {
return { field, order };
};

const defaultFilter = {};

/**
* Render related records to the current one.
*
Expand Down Expand Up @@ -106,79 +92,47 @@ const defaultFilter = {};
* ...
* </ReferenceManyField>
*/
export const ReferenceManyFieldController = ({
export const ReferenceManyFieldController: FunctionComponent<Props> = ({
resource,
reference,
record,
target,
filter = defaultFilter,
filter,
source,
children,
basePath,
perPage = 25,
sort = { field: 'id', order: 'DESC' },
perPage,
sort,
children,
}) => {
const referenceId = get(record, source);
const relatedTo = useMemo(
() => nameRelatedTo(reference, referenceId, resource, target, filter),
[filter, reference, referenceId, resource, target]
);
const ids = useSelector(selectIds(relatedTo), [relatedTo]);
const data = useSelector(selectData(reference, relatedTo), [
reference,
relatedTo,
]);
const total = useSelector(selectTotal(relatedTo), [relatedTo]);
const [page, setPage] = useState(1);
const [currentPerPage, setPerPage] = useState(perPage);
useEffect(() => setPerPage(perPage), [perPage]);
const [currentSort, setSort] = useReducer(sortReducer, sort);
useEffect(() => setSort(sort), [sort.field, sort.order]);

const dispatch = useDispatch();

useEffect(
fetchReferences({
reference,
referenceId,
resource,
target,
filter,
source,
page,
perPage: currentPerPage,
sort: currentSort,
dispatch,
}),
[
reference,
referenceId,
resource,
target,
filter,
source,
crudGetManyReference,
page,
currentPerPage,
currentSort.field,
currentSort.order,
]
);

const referenceBasePath = basePath.replace(resource, reference);

return children({
const {
currentSort,
data,
ids,
loadedOnce,
page,
currentPerPage,
referenceBasePath,
setPage,
setPerPage,
setSort,
total,
} = useReferenceMany({
resource,
reference,
record,
resource,
target,
filter,
source,
basePath,
perPage,
sort,
});

return children({
currentSort,
data,
ids,
loadedOnce: typeof ids !== 'undefined',
loadedOnce,
page,
perPage: currentPerPage,
referenceBasePath,
Expand All @@ -189,44 +143,4 @@ export const ReferenceManyFieldController = ({
});
};

const fetchReferences = ({
reference,
referenceId,
resource,
target,
filter,
source,
dispatch,
page,
perPage,
sort,
}) => () => {
const relatedTo = nameRelatedTo(
reference,
referenceId,
resource,
target,
filter
);

dispatch(
crudGetManyReference(
reference,
target,
referenceId,
relatedTo,
{ page, perPage },
sort,
filter,
source
)
);
};

const selectData = (reference, relatedTo) => state =>
getReferences(state, reference, relatedTo);

const selectIds = relatedTo => state => getIds(state, relatedTo);
const selectTotal = relatedTo => state => getTotal(state, relatedTo);

export default ReferenceManyFieldController;
177 changes: 177 additions & 0 deletions packages/ra-core/src/controller/field/useReferenceMany.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { ReactNode, useState, useReducer, useEffect, useMemo } from 'react';
// @ts-ignore
import { useSelector, useDispatch } from 'react-redux';
import get from 'lodash/get';

import { crudGetManyReference } from '../../actions';
import {
SORT_ASC,
SORT_DESC,
} from '../../reducer/admin/resource/list/queryReducer';
import {
getIds,
getReferences,
getTotal,
nameRelatedTo,
} from '../../reducer/admin/references/oneToMany';
import { Record, Sort, RecordMap, Identifier, Dispatch } from '../../types';

interface ChildrenFuncParams {
currentSort: Sort;
data: RecordMap;
ids: Identifier[];
loadedOnce: boolean;
page: number;
currentPerPage: number;
referenceBasePath: string;
setPage: (page: number) => void;
setPerPage: (perPage: number) => void;
setSort: (field: string) => void;
total: number;
}

interface Options {
basePath: string;
data?: RecordMap;
filter?: any;
ids?: any[];
loadedOnce?: boolean;
perPage?: number;
record?: Record;
reference: string;
resource: string;
sort?: Sort;
source: string;
target: string;
total?: number;
}

const sortReducer = (state: Sort, field: string | Sort): Sort => {
if (typeof field !== 'string') {
return field;
}
const order =
state.field === field && state.order === SORT_ASC
? SORT_DESC
: SORT_ASC;
return { field, order };
};

const defaultFilter = {};

const useReferenceMany = ({
resource,
reference,
record,
target,
filter = defaultFilter,
source,
basePath,
perPage = 25,
sort = { field: 'id', order: 'DESC' },
}: Options): ChildrenFuncParams => {
const referenceId = get(record, source);
const relatedTo = useMemo(
() => nameRelatedTo(reference, referenceId, resource, target, filter),
[filter, reference, referenceId, resource, target]
);
const ids = useSelector(selectIds(relatedTo), [relatedTo]);
const data = useSelector(selectData(reference, relatedTo), [
reference,
relatedTo,
]);
const total = useSelector(selectTotal(relatedTo), [relatedTo]);
const [page, setPage] = useState(1);
const [currentPerPage, setPerPage] = useState(perPage);
useEffect(() => setPerPage(perPage), [perPage]);
const [currentSort, setSort] = useReducer(sortReducer, sort);
useEffect(() => setSort(sort), [sort.field, sort.order]);

const dispatch = useDispatch();

useEffect(
fetchReferences({
reference,
referenceId,
resource,
target,
filter,
source,
page,
perPage: currentPerPage,
sort: currentSort,
dispatch,
}),
[
reference,
referenceId,
resource,
target,
filter,
source,
crudGetManyReference,
page,
currentPerPage,
currentSort.field,
currentSort.order,
]
);

const referenceBasePath = basePath.replace(resource, reference);

return {
currentSort,
data,
ids,
loadedOnce: typeof ids !== 'undefined',
page,
currentPerPage,
referenceBasePath,
setPage,
setPerPage,
setSort,
total,
};
};

const fetchReferences = ({
reference,
referenceId,
resource,
target,
filter,
source,
dispatch,
page,
perPage,
sort,
}) => () => {
const relatedTo = nameRelatedTo(
reference,
referenceId,
resource,
target,
filter
);

dispatch(
crudGetManyReference(
reference,
target,
referenceId,
relatedTo,
{ page, perPage },
sort,
filter,
source
)
);
};

const selectData = (reference, relatedTo) => state =>
getReferences(state, reference, relatedTo);

const selectIds = relatedTo => state => getIds(state, relatedTo);
const selectTotal = relatedTo => state => getTotal(state, relatedTo);

export default useReferenceMany;

0 comments on commit af98d09

Please sign in to comment.