ReactでError: Invalid hook call.

React AdminでSelectArrayInputのchoicesをリモートapiから動的に呼び出そうとしたら、以下のようなエラーが出た。

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app
    See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

実際の問題のコードの箇所は下記。

//choicesに使用するロールをapiから呼び出す。
const getRoles =  ():any[] => {
    const result = useGetList("roles");
    const items = result.data || [];
    return items.map((v) => {
        return {
            id:v.originId,
            name:v.name
        };
    });
};

const UserFilters = [
    <TextInput label="ユーザー名" source="username" alwaysOn={true} />,
    <SelectArrayInput label="権限" source="roles" choices={getRoles()} />
];
const UserList = () => {
    return (
        <List exporter={false} filters={UserFilters}>
            <Datagrid rowClick="edit">
                <TextField source="username" label="ユーザー名" />
                <TextField source="roleNames" label="権限" />
                <ShowButton />
                <EditButton />
            </Datagrid>
        </List>
    )
};

フックはメソッドのトップレベルでしか呼び出せないとのことで、メソッド外からは呼び出せないようです。

上記はメソッドの外で呼び出してしてしまっているからエラーなんですかね。

以下のようにUserListの内側にUserFilterを定義して、その中でgetRoles()を呼び出すように修正することで対応できました。


const UserList = () => {
    //ここで呼び出す
    const UserFilters = [
        <TextInput label="ユーザー名" source="username" alwaysOn={true} />,
        <SelectArrayInput label="権限" source="roles" choices={getRoles()} />
    ];
    return (
        <List exporter={false} filters={UserFilters}>
            <Datagrid rowClick="edit">
                <TextField source="username" label="ユーザー名" />
                <TextField source="roleNames" label="権限" />
                <ShowButton />
                <EditButton />
            </Datagrid>
        </List>
    )
};