Creating new record does not register in list without refresh and creates duplicate record - react-admin

Below is a screenshot of the Redux dev tools. This is a list of records of a particular resource. As you can see, the newly added record has a duplicate with the key undefined. It also does not register on the list without a refresh.
Redux Dev Tools
Here is the create component:
export const OrgCreate = (props: ReactAdminComponentProps) => {
const controller = useCreateController(props);
return (
<Create {...props} {...controller}>
<SimpleForm>
<TextInput source="name" />
</SimpleForm>
</Create>
);
};
Here is the list component:
export const OrgList = (props: ReactAdminComponentProps) => {
const controller = useListController(props);
return (
<List {...props} {...controller} exporter={false} bulkActionButtons={false}>
<Datagrid rowClick="edit" hasBulkActions={false}>
<TextField source="name.value" label="Name" />
<DateField source="createdAt" />
</Datagrid>
</List>
);
};
Here is the create response in the GraphQL provider:
createResponse = (data: any) => data.createOrganization.organization;

Try removing the lines:
const controller = useCreateController(props);
const controller = useListController(props);
and further {...controller}, it should work.

Related

specific ID in react-admin list

would like to get the id of a row when I click on a button or somewhere on the row inside the list/Datagrid component of react-admin,
I am completely new to react js and react-admin as well.
WOuld appreciate for any kind gesture
React-admin exposes a hook called useRecordContext that lets you access the record used by the current component. In a Datagrid, this lets you access the record of the row.
So you can create a component like so:
import { useRecordContext } from 'react-admin';
const MyButton = () => {
const record = useRecordContext();
const handleClick = () => {
// the current row id is record.id
// do something with it
};
return <button onClick={handleClick}>Do stuff</button>;
}
Then, use that component as a child of <Datagrid>:
const MyList = () => (
<List>
<Datagrid>
<TextField source="title" />
<MyButton />
</Datagrid>
</List>
);
More information at https://marmelab.com/react-admin/useRecordContext.html

how do I pass ref to state?

I created a ref and passed it to the component as an argument. Now how can I write it to State without dispatch?
const myRef = createRef<any>();
const KeyboardAvoidingWrapper: React.FC<IKeyboardAvoidingProps> = (
props: IKeyboardAvoidingProps,
=> {
if (isAndroid) {
return (
<ScrollView ref={myRef} style={styles.scroll} contentContainerStyle={styles.scrollContent}>
<KeyboardAvoiding>{props.children}</KeyboardAvoiding>
</ScrollView>
);
}
This example might help you.
<Component ref={(ref) => {
// You can now write ref to state,
// which I will not recommend
// or pass it to callback
props.getInnerRef(ref);
}} />
// You need to pass getInnerRef
<Component getInnerRef={(ref) => {
this.innerRef = ref;
}}
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
Please refer the react documentation. It clearly defines how to use refs.
ForwadingRefs

React Router V4 restore navigation state from url

Let's say we display a dropdown and on select the user is navigated to a different subpage via react router. How can we restore the dropdown selection on page reload with react router? The projectNumber param is only accessible in the Project component.
In some other projects I solved this problem by writing back the route param to a context or redux store from the child component, but this obviously isn't a nice solution, is it?
export const Projects: React.FC = () => {
const { data, loading, error } = useSomeData()
const history = useHistory()
const onSelectProject = useCallback(
(projectNumber: unknown) => {
history.push(`/project/${projectNumber}`)
},
[history],
)
if (error) return <p>{error.toString()}</p>
return (
<>
<Select loading={loading} onChange={onSelectProject} placeholder="Select a project">
{data?.map((project) => (
<Option key={project.id} value={project.number}>
{project.name}
</Option>
))}
</Select>
<Route path="/project/:projectNumber" render={() => <Project />} />
</>
)
}
You can do it via react-router state. Just see the example:
export const Projects = () => {
const history = useHistory()
const { state } = useLocation()
const onSelectProject = useCallback(
(projectNumber) => {
history.push({
pathname: '/project',
state: {
projectNumber
}
})
},
[history],
)
if (error) return <p>{error.toString()}</p>
return (
<>
<Select loading={loading} onChange={onSelectProject} placeholder="Select a project">
{data?.map((project) => (
<Option key={project.id} value={project.number}>
{project.name}
</Option>
))}
</Select>
{state && state. projectNumber && <Project projectNumber={state.projectNumber} />
</>
)
}
It will work fine for reload page, but not for sharing link to someone other.
But if you are going to share link with preselected dropdown, you can use query parameter (GET parameter).

data empty using ReportUserAction component

I'm using the following code to create an action on a Edit View:
const PostEditActions = ({ basePath, data, resource }) => (
<CardActions>
<ReportUserAction record={data} />
</CardActions>
);
export const UserEdit = (props) => (
<Edit title="Modify user parameters" actions={<PostEditActions />} {...props}>
....
In ReportUserAction component I receive data= undefined, but I don't know why. The edit view has data:
{"data":{"locale":"en","status":"enabled","facebookId":"XXXXX","createdAt":"2016-06-15T20:21:47.000Z",...
And I can access to other variables such as basePath and Resource.
How can I pass data with the correct information?
Thanks

pass user prop to all children react router

I want to write a wrapper component that passes any children props. For example in a pure react auth system.
<Router history={ hashHistory } >
<Route path="/" component={Base}>
<Route component={Auth}>
<Route path="/who" component={Who} />
<Route path="/features" component={Features} />
<Route path="/try" component={Try} />
</Route>
</Route>
</Router>
I want to pass a user by props to either the Who, Features or Try components from Auth, which will pull from local storage.
The silly thing I have tried to do is to manipulate this.props or this.props.children but this is not ok, what is the recommended solution?
class Auth extends Component {
render() {
//find user or null
var user = JSON.parse(localStorage.getItem('user')) || [];
//this.props.user = user;
console.log('top level router props.user', this.props.user);
return (
<div>
{this.props.children}
</div>
);
}
}
see this answer by Jess. React clone element is what you want.
React router and this.props.children - how to pass state to this.props.children
render() {
var childrenWithProps = React.cloneElement(this.props.children, {someProp: this.state.someProp});
return (
<div>
<Header />
{childrenWithProps}
</div>
);
}
If you upgrade to version 4 you can use Match with your own HOC for auth.
https://react-router.now.sh/auth-workflow