I am using React-admin and i am trying to test with the "jsonplaceholder.typicode"
When i compile this code
import { Admin, Resource, ListGuesser } from "react-admin";
import { UserList } from "./users";
const dataProvider = jsonServerProvider("http://jsonplaceholder.typicode.com");
const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="users" list={UserList} />
</Admin>
);
I have this error "call: argument [object Object] is not a function"
what is my mistake?...
Thank's
Use code from documentation https://github.com/marmelab/react-admin/tree/master/packages/ra-data-json-server
import React from 'react';
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { UserList } from './users';
const App = () => (
<Admin dataProvider={jsonServerProvider('http://jsonplaceholder.typicode.com')}>
<Resource name="users" list={UserList} />
</Admin>
);
export default App;
Related
I've integrated MSAL.js 2.0 with react-admin in order to use Azure Active Directory as Auth Provider. Based on react-admin Auth providers samples and links (https://github.com/victorp13/react-admin-msal) I've implemented login. Works great, my react-admin frontend is correctly protected.
But I cannot succeeded to implement logout. If I follow react-admin documentation (https://marmelab.com/react-admin/Authentication.html#uselogout-hook), my LogoutButton.js code is ignored.
Index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { PublicClientApplication, InteractionType } from "#azure/msal-browser";
import { MsalProvider, MsalAuthenticationTemplate } from "#azure/msal-react";
import { msalConfig } from "./authConfig";
const msalInstance = new PublicClientApplication(msalConfig);
ReactDOM.render(
<React.StrictMode>
<MsalProvider instance={msalInstance}>
<MsalAuthenticationTemplate interactionType={InteractionType.Redirect}>
<App />
</MsalAuthenticationTemplate>
</MsalProvider>
</React.StrictMode>,
document.getElementById("root")
);
reportWebVitals();
App.js
import * as React from "react";
import { Admin, Resource, ListGuesser, fetchUtils } from "react-admin";
import dataProvider from "./dataProvider";
import LogoutButton from './LogoutButton';
const App = () => (
<Admin dataProvider={dataProvider} logoutButton={LogoutButton}>
<Resource name="users" list={ListGuesser} />
</Admin>
);
export default App;
LogoutButton.js
import * as React from 'react';
import { forwardRef } from 'react';
import { useLogout } from 'react-admin';
import MenuItem from '#material-ui/core/MenuItem';
import ExitIcon from '#material-ui/icons/PowerSettingsNew';
import { PublicClientApplication } from "#azure/msal-browser";
import { msalConfig } from "./authConfig";
const LogoutButton = forwardRef((props, ref) => {
const logout = useLogout();
const handleClick = () => {
console.log('Logout button never clicked!');
const msalInstance = new PublicClientApplication(msalConfig);
msalInstance.logoutRedirect();
logout();
};
return (
<MenuItem
onClick={handleClick}
ref={ref}
>
<ExitIcon /> Disconnect
</MenuItem>
);
});
export default LogoutButton;
Any ideas to help? Thanks!
Regards
You need to use an authProvider in order to properly use the auth functions given by react-admin. If you can share your console errors when clicking, I think I could have more insight. Still, first thing I would do is override the logout function from the authProvider , the following is the interface for writing your own. What you want to do is take out all the logic from your handleClick function, and only leave the logout() callback. Then the msal logic, you want to put it inside logout, something like this.
import { AuthProvider } from 'react-admin';
const authProvider = {
// authentication
login: ({ username, password }) => { /* ... */ },
checkError: (error) => { /* ... */ },
checkAuth: () => { /* ... */ },
logout: () => {
console.log('Logout button never clicked!');
const msalInstance = new PublicClientApplication(msalConfig);
msalInstance.logoutRedirect();
},
getIdentity: () => { /* ... */ },
// authorization
getPermissions: (params) => { /* ... */ },
}.
I want to redirect my current app screen to login screen if the user is not authenticated. So I created a global component RedirectorToLogin and use this component in my App.js . But I'm getting this error Couldn't find a navigation object. Is your component inside a screen in a navigator ? because I'm using useNavigation inside RedirectorToLogin.
What is the reason for this error to be occured ?
My RedirectorToLogin.js
import React, { useContext, useEffect } from 'react'
import { useNavigation } from '#react-navigation/native'
import AuthGlobal from '../Context/store/AuthGlobal'
const RedirectorToLogin = (props) => {
const context = useContext(AuthGlobal)
const navigation = useNavigation()
useEffect(() => {
if (!context.stateUser.isAuthenticated) {
navigation.navigate('Login')
}
return () => {}
}, [context.stateUser.isAuthenticated])
return <></>
}
export default RedirectorToLogin
My App.js
import { StatusBar } from 'expo-status-bar'
import React from 'react'
import { LogBox } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
import Toast from 'react-native-toast-message'
import ErrorBoundary from 'react-native-error-boundary'
// Redux
import { Provider } from 'react-redux'
import store from './Redux/store'
// Context API
import Auth from './Context/store/Auth'
// Navigatiors
import Main from './Navigators/Main'
// Screens
import Header from './Shared/Header'
import MyAppState from './Global/MyAppState'
import Network from './Global/Network'
import RedirectorToLogin from './Global/RedirectorToLogin'
const errorHandler = (error, stackTrace) => {
/* Log the error to an error reporting service */
console.log('**** error log form error handler ****')
console.log(error)
console.log(stackTrace)
console.log('**** **** ****')
}
LogBox.ignoreAllLogs(true)
export default function App() {
return (
<ErrorBoundary onError={errorHandler}>
<Auth>
<Provider store={store}>
<NavigationContainer>
<Header />
<Main />
<MyAppState />
<Network />
<RedirectorToLogin />
<Toast ref={(ref) => Toast.setRef(ref)} />
</NavigationContainer>
</Provider>
</Auth>
</ErrorBoundary>
)
}
I referred to this article and updated my Main.js to show only login navigator when user is not authenticated. So I can get rid of having RedirectorToLogin
using react-admin i created an app with sample list with many pages then i ran it. if i opened another page in the list and chose to edit a row or to delete it, the task done but the list is redirected to the first page and this is not good for user experience. if the user want to review multiple rows and edit them this will oblige him to return to the page each time he made edit. i am not sure if this is a how to question or a bug or feature that should be posted in github. i tested it in multiple react-admin versions 3.6.0, 3.5.5, 3.0.0 and the same behavior appeared.
// in src/App.js
import * as React from "react";
import { Admin, Resource } from "react-admin";
import jsonServerProvider from "ra-data-json-server";
import CommentList from "./comments";
const dataProvider = jsonServerProvider("https://jsonplaceholder.typicode.com");
const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="comments" list={CommentList} />
</Admin>
);
export default App;
import * as React from "react";
import {
List,
Datagrid,
TextField,
ReferenceField,
EmailField
} from "react-admin";
import { Fragment } from "react";
import { BulkDeleteButton } from "react-admin";
import ResetViewsButton from "./ResetViewsButton";
const PostBulkActionButtons = props => (
<Fragment>
<ResetViewsButton label="Reset Views" {...props} />
{/* default bulk delete action */}
<BulkDeleteButton {...props} />
</Fragment>
);
const CommentList = props => (
<List {...props} bulkActionButtons={<PostBulkActionButtons />}>
<Datagrid rowClick="edit">
<ReferenceField source="postId" reference="posts">
<TextField source="id" />
</ReferenceField>
<TextField source="id" />
<TextField source="name" />
<EmailField source="email" />
<TextField source="body" />
</Datagrid>
</List>
);
export default CommentList;
import * as React from "react";
import { Button, useUpdateMany, useNotify, useUnselectAll } from "react-admin";
import { VisibilityOff } from "#material-ui/icons";
const ResetViewsButton = props => {
const notify = useNotify();
const unselectAll = useUnselectAll();
console.log(props.selectedIds);
console.log(props.basePath);
const [updateMany, { loading }] = useUpdateMany(
"comments",
props.selectedIds,
{ emails: "" },
{
onSuccess: () => {
notify("comments updated");
unselectAll("comments");
},
onFailure: error => notify("Error: comments not updated", "warning")
}
);
return (
<Button
label="simple.action.resetViews"
disabled={loading}
onClick={updateMany}
>
<VisibilityOff />
</Button>
);
};
export default ResetViewsButton;
You can use "useRedirect" If I am not getting you wrong. You want to redirect after edit info.
import { useRedirect } from 'react-admin';
const ResetViewsButton = props => {
const notify = useNotify();
const redirectTo = useRedirect();
const unselectAll = useUnselectAll();
console.log(props.selectedIds);
console.log(props.basePath);
const [updateMany, { loading }] = useUpdateMany(
"comments",
props.selectedIds,
{ emails: "" },
{
onSuccess: () => {
notify("comments updated");
unselectAll("comments");
redirectTo('/url');
},
onFailure: error => notify("Error: comments not updated", "warning")
}
);
return (
<Button
label="simple.action.resetViews"
disabled={loading}
onClick={updateMany}
>
<VisibilityOff />
</Button>
);
};
export default ResetViewsButton;
it was a bug. wait version 3.6.1
I apply the navigation example without the navigation prop of the react-navigations docs (NavigationService), but I can't make it work with react-i18next.
I applied the example of the documentation https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html in my code:
// App.js
import React from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/lib/integration/react';
import { createAppContainer } from 'react-navigation';
import { I18nextProvider, withNamespaces } from 'react-i18next';
import { persistor, store } from './src/store';
import I18n from './src/localization';
import Navigation from './src/navigation';
import NavigationService from './src/navigation/NavigationService';
import Loader from './src/screens/components/Loader';
class NavigationStack extends React.Component {
static router = Navigation.router;
render() {
const { t } = this.props;
return <Navigation screenProps={{ t, I18n }} {...this.props} />;
}
};
const ReloadNavOnLanguageChange = withNamespaces(['common', 'server'], {
bindI18n: 'languageChanged',
bindStore: false,
})(createAppContainer(NavigationStack));
export default class App extends React.Component {
...
render() {
return (
<Provider store={store}>
<PersistGate loading={<Loader />} persistor={persistor}>
<I18nextProvider i18n={ I18n } >
<ReloadNavOnLanguageChange ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}} />
</I18nextProvider>
</PersistGate>
</Provider>
);
};
};
// Navigation.js
...
export default Navigation = createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
Login: LoginScreen,
App: AppScreen
},
{
initialRouteName: 'AuthLoading'
}
);
// NavigationService.js
Apply the same code that's in https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html
// Any JS module of my project (actions, helpers, components, etc.)
import NavigationService from 'path-to-NavigationService.js';
...
NavigationService.navigate('Login');
When the authorization token is validated and the result is negative, the login screen must be opened (NavigationService.navigate('Login')) but it returns the error _navigator.dispatch is not a function in NavigationService.js:
const navigate = (routeName, params) => {
// DISPATCH ERROR
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params
})
);
};
Dependencies:
react 16.5.0
react-native 57.1
react-i18next 9.0.0
react-navigation 3.1.2
Any suggestion? Has anyone else found this scenario?
Using the innerRef option of the withNamespaces hoc of react-i18next instead of passing the function through the ref property of the root component… AS THE DOCUMENTATION OF REACT-I18NETX SAYS!
// App.js
...
const ReloadNavOnLanguageChange = withNamespaces(['common', 'server'], {
bindI18n: 'languageChanged',
bindStore: false,
innerRef: (ref) => NavigationService.setTopLevelNavigator(ref)
})(createAppContainer(NavigationStack));
export default class App extends React.Component {
...
render() {
return (
...
<ReloadNavOnLanguageChange />
...
);
};
}
Hello I am trying a simple example for redux-observable. This is an example signup for a user. The appplication doesnt even start.I get the error in the end. I am getting an undefined epics array when I debug in chrome. I dont understand what I am missing. Can you please help me ?
Below is combineepics
import {combineEpics} from "redux-observable";
import { ajax } from 'rxjs/observable/dom/ajax';
import { map, catchError, mergeMap } from 'rxjs/operators'
import {ofType} from 'redux-observable'
import { merge } from 'rxjs/observable/merge';
import { createUserSuccess ,CREATE_USER_FAILURE,CREATE_USER} from '../actions/createUser';
const createUserEpic = action$ => action$.pipe(
ofType(CREATE_USER),
mergeMap(action => ajax.post("http://localhost:8080/signup", action.payload).pipe(
map(response => createUserSuccess(response)),
catchError(error => of({
type: CREATE_USER_FAILURE,
payload: error.xhr.response,
error: true
}))
))
);
const rootEpic = combineEpics(
createUserEpic
);
export default rootEpic;
Store and middleware initialization:
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { createEpicMiddleware } from 'redux-observable';
import PostsIndex from "./components/posts_index";
import reducers from "./reducers";
import epics from "./epics";
//import PostsIndex from "./components/posts_index";
import Login from "./components/login";
import Signup from "./components/signup";
//import PostsShow from "./components/posts_show";
const epicMiddleware = createEpicMiddleware();
const createStoreWithMiddleware = applyMiddleware(epicMiddleware)(createStore);
const store = createStoreWithMiddleware(reducers);
epicMiddleware.run(epics);
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<div>
<Switch>
<Route path="/signup" component={Signup} />
<Route path="/" component={Login} />
</Switch>
</div>
</BrowserRouter>
</Provider>,
document.querySelector(".container")
);
createUser.js
export const CREATE_USER = "create_user";
export const CREATE_USER_FAILURE = "create_user_failure"
const ROOT_URL = "http://localhost:8080/signup";
const API_KEY = "?key=PAPERCLIP1234";
export function createUserSuccess(response) {
return {
type: CREATE_USER,
payload: response
};
}
export function createUserFailure(error) {
return {
type: CREATE_USER_FAILURE,
payload: error
};
}
Uncaught TypeError: Cannot read property 'apply' of undefined
at merger (combineEpics.js:22)
at MapSubscriber.eval [as project] (createEpicMiddleware.js:36)
at MapSubscriber._next (map.js:79)
at MapSubscriber.Subscriber.next (Subscriber.js:93)
at Subject.next (Subject.js:55)
at Function.epicMiddleware.run (createEpicMiddleware.js:70)
at eval (index.js:49)
at Object../src/index.js (bundle.js:10320)
at __webpack_require__ (bundle.js:20)
at eval (webpack:///multi_(webpack)-dev-server/client?:2:18)
The problem was with older version of rxjs. we need to update the rxjs verison to 6.
"redux-observable": "^1.0.0",
"rxjs": "^6.0.0",
"rxjs-compat": "^6.3.3"