Skip to content

Commit

Permalink
rename useReference to useReferenceField and add more generic useRefe…
Browse files Browse the repository at this point in the history
…rence
  • Loading branch information
ThieryMichel committed Jun 13, 2019
1 parent 47e47a6 commit fe9342a
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { FunctionComponent, ReactNode, ReactElement } from 'react';
import { Record } from '../../types';
import useReference, { UseReferenceProps } from './useReference';

import useReferenceField, { UseReferenceProps } from './useReferenceField';

interface Props {
allowEmpty?: boolean;
Expand Down Expand Up @@ -47,7 +46,7 @@ export const ReferenceFieldController: FunctionComponent<Props> = ({
children,
...props
}) => {
return children(useReference(props)) as ReactElement<any>;
return children(useReferenceField(props)) as ReactElement<any>;
};

export default ReferenceFieldController;
4 changes: 2 additions & 2 deletions packages/ra-core/src/controller/field/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import ReferenceArrayFieldController from './ReferenceArrayFieldController';
import ReferenceFieldController from './ReferenceFieldController';
import ReferenceManyFieldController from './ReferenceManyFieldController';
import useReference from './useReference';
import useReferenceField from './useReferenceField';
import useReferenceArray from './useReferenceArray';
import useReferenceMany from './useReferenceMany';

export {
useReferenceArray,
ReferenceArrayFieldController,
ReferenceFieldController,
useReference,
useReferenceField,
useReferenceMany,
ReferenceManyFieldController,
};
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import { useEffect } from 'react';
// @ts-ignore
import { useDispatch, useSelector } from 'react-redux';
import get from 'lodash/get';

import { crudGetManyAccumulate } from '../../actions';
import { linkToRecord } from '../../util';
import { Record, ReduxState } from '../../types';
import { Record } from '../../types';
import useReference from '../useReference';

interface Option {
allowEmpty?: boolean;
basePath: string;
record?: Record;
source: string;
reference: string;
resource: string;
source: string;
linkType: string | boolean;
}

Expand Down Expand Up @@ -58,39 +55,31 @@ export interface UseReferenceProps {
*
* @returns {ReferenceProps} The reference props
*/
export const useReference = ({
export const useReferenceField = ({
allowEmpty = false,
basePath,
linkType = 'edit',
record = { id: '' },
reference,
record = { id: '' },
resource,
source,
}: Option): UseReferenceProps => {
const sourceId = get(record, source);
const referenceRecord = useSelector(
getReferenceRecord(sourceId, reference)
);
const dispatch = useDispatch();
useEffect(() => {
if (sourceId !== null && typeof sourceId !== 'undefined') {
dispatch(crudGetManyAccumulate(reference, [sourceId]));
}
}, [sourceId, reference]);
const { referenceRecord, isLoading } = useReference({
id: sourceId,
reference,
allowEmpty,
});
const rootPath = basePath.replace(resource, reference);
const resourceLinkPath = !linkType
? false
: linkToRecord(rootPath, sourceId, linkType as string);

return {
isLoading: !referenceRecord && !allowEmpty,
isLoading,
referenceRecord,
resourceLinkPath,
};
};

const getReferenceRecord = (sourceId, reference) => (state: ReduxState) =>
state.admin.resources[reference] &&
state.admin.resources[reference].data[sourceId];

export default useReference;
export default useReferenceField;
39 changes: 7 additions & 32 deletions packages/ra-core/src/controller/input/ReferenceInputController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ import { useSelector, useDispatch } from 'react-redux';
import { createSelector } from 'reselect';
import { WrappedFieldInputProps } from 'redux-form';

import {
crudGetManyAccumulate,
crudGetMatchingAccumulate,
} from '../../actions/accumulateActions';
import { crudGetMatchingAccumulate } from '../../actions/accumulateActions';
import {
getPossibleReferences,
getPossibleReferenceValues,
Expand All @@ -25,6 +22,7 @@ import { Sort, Record, Pagination } from '../../types';
import usePaginationState from '../usePaginationState';
import useSortState from '../useSortState';
import useFilterState, { Filter } from '../useFilterState';
import useReference from '../useReference';

const defaultReferenceSource = (resource: string, source: string) =>
`${resource}@${source}`;
Expand Down Expand Up @@ -164,10 +162,11 @@ export const ReferenceInputController: FunctionComponent<Props> = ({
[input.value, referenceSource, reference, source, resource]
);

const referenceRecord = useSelector(
getSelectedeference({ input, reference }),
[input.value, reference]
);
const { referenceRecord } = useReference({
id: input.value,
reference,
allowEmpty: true,
});

const dataStatus = getDataStatus({
input,
Expand All @@ -183,16 +182,6 @@ export const ReferenceInputController: FunctionComponent<Props> = ({
filterToQuery,
});

useEffect(
() =>
fetchReference({
dispatch,
id: input.value,
reference,
}),
[input.value, reference]
);

useEffect(
() =>
fetchOptions({
Expand Down Expand Up @@ -233,12 +222,6 @@ export const ReferenceInputController: FunctionComponent<Props> = ({
}) as ReactElement;
};

const fetchReference = ({ dispatch, id, reference }) => {
if (id) {
dispatch(crudGetManyAccumulate(reference, [id]));
}
};

const fetchOptions = ({
dispatch,
filter,
Expand Down Expand Up @@ -273,12 +256,4 @@ const matchingReferencesSelector = createSelector(
const getMatchingReferences = props => state =>
matchingReferencesSelector(state, props);

const selectedReferenceSelector = createSelector(
[getReferenceResource, (_, props) => props.input.value],
(referenceState, inputId) => referenceState && referenceState.data[inputId]
);

const getSelectedeference = props => state =>
selectedReferenceSelector(state, props);

export default ReferenceInputController as ComponentType<Props>;
75 changes: 75 additions & 0 deletions packages/ra-core/src/controller/useReference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useEffect } from 'react';
// @ts-ignore
import { useDispatch, useSelector } from 'react-redux';

import { crudGetManyAccumulate } from '../actions';
import { Record } from '../types';
import { getReferenceResource } from '../reducer';
import { createSelector } from 'reselect';

interface Option {
id: string;
reference: string;
allowEmpty?: boolean;
}

export interface UseReferenceProps {
isLoading: boolean;
referenceRecord: Record;
}

/**
* @typedef ReferenceProps
* @type {Object}
* @property {boolean} isLoading: boolean indicating if the reference has loaded
* @property {Object} referenceRecord: the referenced record.
*/

/**
* Fetch reference record, and return it when avaliable
*
* The reference prop sould be the name of one of the <Resource> components
* added as <Admin> child.
*
* @example
*
* const { isLoading, referenceRecord } = useReference({
* id: 7,
* reference: 'users',
* });
*
* @param {Object} option
* @param {boolean} option.allowEmpty do we allow for no referenced record (default to false)
* @param {string} option.reference The linked resource name
* @param {string} option.id The id of the reference
*
* @returns {ReferenceProps} The reference record
*/
export const useReference = ({
allowEmpty = false,
reference,
id,
}: Option): UseReferenceProps => {
const referenceRecord = useSelector(getReferenceRecord({ id, reference }));
const dispatch = useDispatch();
useEffect(() => {
if (id !== null && typeof id !== 'undefined') {
dispatch(crudGetManyAccumulate(reference, [id]));
}
}, [id, reference]);

return {
isLoading: !referenceRecord && !allowEmpty,
referenceRecord,
};
};

const selectedReferenceSelector = createSelector(
[getReferenceResource, (_, props) => props.id],
(referenceState, id) => referenceState && referenceState.data[id]
);

const getReferenceRecord = props => state =>
selectedReferenceSelector(state, props);

export default useReference;
4 changes: 2 additions & 2 deletions packages/ra-ui-materialui/src/field/ReferenceField.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Children } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { withStyles, createStyles } from '@material-ui/core/styles';
import { useReference } from 'ra-core';
import { useReferenceField } from 'ra-core';

import LinearProgress from '../layout/LinearProgress';
import Link from '../Link';
Expand Down Expand Up @@ -120,7 +120,7 @@ const ReferenceField = ({ children, ...props }) => {
throw new Error('<ReferenceField> only accepts a single child');
}

const { isLoading, referenceRecord, resourceLinkPath } = useReference(props);
const { isLoading, referenceRecord, resourceLinkPath } = useReferenceField(props);

return (
<ReferenceFieldView
Expand Down

0 comments on commit fe9342a

Please sign in to comment.