I got a legacy project of Meteor and React and I try to make it work. But I got an error at one point. Can anyone help me to resolve following error?
Uncaught Error: Objects are not valid as a React child (found: object with keys {$$typeof, type, compare}). If you meant to render a collection of children, use an array instead.
in Unknown
in main (created by Basic)
in Basic (created by Context.Consumer)
in Content (created by PageLayout)
in section (created by BasicLayout)
in BasicLayout (created by Context.Consumer)
in Layout (created by PageLayout)
in section (created by BasicLayout)
in BasicLayout (created by Context.Consumer)
in Layout (created by PageLayout)
in section (created by BasicLayout)
in BasicLayout (created by Context.Consumer)
in Layout (created by PageLayout)
in LocaleProvider (created by Context.Consumer)
in LocaleReceiver (created by ConfigProvider)
in ConfigProvider (created by PageLayout)
in PageLayout (created by ForwardRef)
in ForwardRef
in ForwardRef
at throwOnInvalidObjectType (modules.js:64084)
at reconcileChildFibers (modules.js:64984)
at reconcileChildren (modules.js:67433)
at mountIndeterminateComponent (modules.js:68213)
at beginWork (modules.js:69267)
at HTMLUnknownElement.callCallback (modules.js:50859)
at Object.invokeGuardedCallbackDev (modules.js:50908)
at invokeGuardedCallback (modules.js:50963)
at beginWork$1 (modules.js:73874)
at performUnitOfWork (modules.js:72828)
Within the secure.js
the PostCategories
are mounted like this
ContentRouter.route('/content-creator', {
name: 'Content Creator',
icon: 'solution',
permission: 'main-navigation.view.module.posts',
className: 'posts',
visible: true,
action: () => {
mount(PageLayout, { content: <PostCategories /> });
},
});
The PageLayout
looks like this :
import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';
import React, { Component } from 'react';
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
import Konami from 'react-konami-code';
import deDE from 'antd/lib/locale-provider/de_DE';
import moment from 'moment';
import 'moment/locale/de';
import {
ConfigProvider, Layout, Menu, Icon, Steps, Badge, Button, message,
} from 'antd';
import { Workspaces } from '../../../api/workspaces/collection';
import DoneStepper from './components/doneStepper';
import { DASHBOARD_VERSION } from '../../../helpers/Constants';
const {
Header, Content, Sider, Footer,
} = Layout;
moment.locale('de');
class PageLayout extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
logout = () => {
Meteor.logout(() => {
FlowRouter.go('/anmelden');
});
};
renderMenuItems = () => {
const groupName = FlowRouter.current().route.group.name;
const items = FlowRouter._routes.map((route) => {
const isSecure = route && route.group && route.group.parent && route.group.parent && route.group.parent.name === 'secure';
const isVisible = route && route.options && route.options.visible && route.options.visible === true;
const isActive = groupName === route.group.name;
let active = null;
if (isActive) {
active = 'ant-menu-item-selected';
}
return (
isVisible
&& isSecure && (
<Menu.Item key={route.path} style={route.options.style} className={[route.options.className, active]}>
<a href={route.path}>
<Icon type={route.options.icon} />
<span className="nav-text">{route.name}</span>
</a>
</Menu.Item>
)
);
});
return items;
};
easterEgg = () => {
message.success('Development Mode enabled');
};
handleResetWorkspace = () => {
const { user } = this.props;
Meteor.call('workspace.reset', user.profile.workspace, (error) => {
if (error) {
console.log(error);
message.error('error');
} else {
message.success('success');
}
});
};
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error: error };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
console.log('ERROR IS:');
console.log(this.state.error);
return <h1>Something went wrong.</h1>;
}
const { ready, user, workspace, content } = this.props;
if (ready) {
if (workspace && workspace.appName && workspace.appName.name) {
document.title = `App - ${workspace.appName.name}`;
} else {
document.title = 'App';
}
}
return (
<ConfigProvider locale={deDE}>
<Layout className="manager-dashboard">
<Header className="header">
<div className="logo__area">
<a href="/">
<img className="logo" src="/logo.svg" alt="cms" />
</a>
</div>
<DoneStepper />
<Konami action={this.easterEgg}>
<Button type="primary" onClick={() => this.handleResetWorkspace()}>
<Icon type="delete" size="small" />
{'reset workspace'}
</Button>
</Konami>
<div className="member">
<a onClick={this.logout}>
{'Abmelden '}
<Icon type="logout" />
</a>
</div>
</Header>
<Layout>
<Sider width={200} style={{ background: '#fff' }}>
<div className="fixed-sidebar">
<Menu
defaultSelectedKeys={[FlowRouter.current().route.path]}
selectedKeys={[FlowRouter.current().route.path]}
>
{this.renderMenuItems()}
</Menu>
</div>
</Sider>
<Layout className="dashboard__content">
<Content
style={{
background: '#fff',
padding: 20,
minHeight: '100vh',
}}
>
{content}
</Content>
<Footer>{`App - Version ${DASHBOARD_VERSION}`}</Footer>
</Layout>
</Layout>
</Layout>
</ConfigProvider>
);
}
}
export default withTracker(() => {
const user = Meteor.user();
const handleWorkspace = Meteor.subscribe('workspaces.one', {
query: { _id: user.profile.workspace },
fields: { appName: 1 },
});
const ready = handleWorkspace.ready();
let workspace = null;
if (ready) {
workspace = Workspaces.findOne({ _id: user.profile.workspace }, { fields: { appName: 1 } });
}
return {
ready,
user,
workspace,
};
})(PageLayout);
And the PostCategories
look like this:
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
import { PostCategories } from '/imports/api/posts/collection';
import React, { Component } from 'react';
import Role from '/imports/helpers/Role';
import CreatePostCategory from '/imports/ui/secure/partials/forms/createPostCategory.js';
import {
Card, Button, message, Row, Col, Icon, Switch, Popover,
} from 'antd';
import Text from '../../components/Text.js';
import Preview from '../../components/preview/index.js';
import CustomSpinner from '../../components/custom-spinner';
const DragIndicator = () => (
<svg viewBox="0 0 14 5" height="15" width="15" xmlns="http://www.w3.org/2000/svg">
<path d="m0 0h14v.83823529h-14z" />
<path d="m0 2h14v.83823529h-14z" />
<path d="m0 4h14v.83823529h-14z" />
</svg>
);
const getItemStyle = (isDragging, draggableStyle) => ({
userSelect: 'none',
...draggableStyle,
});
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
class Categories extends Component {
constructor(props) {
super(props);
this.state = {
categories: props.categories,
createCategory: false,
justReorder: false,
deletePopoverVisible: {},
};
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.ready && !prevState.justReorder) {
prevState.categories = nextProps.categories;
prevState.justReorder = false;
} else {
prevState.justReorder = false;
}
return prevState;
}
handleCategoryState = (id, checked) => {
Meteor.call('post.category.state', id, checked, (error) => {
if (error) {
console.log(error);
message.error('error');
} else {
message.success('success');
}
});
};
handleDeletePopoverVisibleChange = (change, id) => {
this.state.deletePopoverVisible[id] = change;
this.setState(this.state);
};
handleDelete = (e, id) => {
e.preventDefault();
Meteor.call('post.category.delete', id, (error) => {
if (error) {
console.log(error);
message.error('error');
} else {
message.success('success');
}
});
};
handleCreateCategory = (e) => {
e.preventDefault();
const form = this.createCategoryForm;
form.validateFieldsAndScroll((err, values) => {
if (err) {
return;
}
values.workspace = this.props.user.profile.workspace;
values.index = this.props.categories.length + 1;
Meteor.call('post.category.insert', values, (error) => {
if (error) {
console.log(error);
message.error('error');
} else {
message.success('success');
form.resetFields();
this.setState({ createCategory: false, categoryId: null });
}
});
});
};
onDragEnd = (data) => {
console.log(data);
const { source, destination, draggableId } = data;
if (!destination) {
return;
}
if (source.droppableId === destination.droppableId) {
this.state.categories = reorder(this.state.categories, data.source.index, data.destination.index);
this.state.categories.forEach((category, idx) => (category.index = idx));
this.state.justReorder = true;
this.setState(this.state, () => {
Meteor.call('post.category.reorder', { categories: this.state.categories }, (error, result) => {
if (error) {
console.log(error);
message.error('error.');
}
});
});
}
};
render() {
const { ready, categories } = this.props;
const { categories: stateCategories, deletePopoverVisible, createCategory } = this.state;
let content = <CustomSpinner />;
if (ready) {
content = (
<Col>
<Row gutter={40}>
<Col xs={24} lg={16} xxl={18}>
{!Array.isArray(categories) ? (
<Row gutter={40}>
<Col
xs={{ span: 24 }}
lg={{ span: 18, offset: 3 }}
xl={{ span: 12, offset: 6 }}
style={{ textAlign: 'center' }}
>
<img src="/emptystates/contentcreator.svg" alt="empty dashboard" />
</Col>
<Col
xs={{ span: 24 }}
lg={{ span: 18, offset: 3 }}
xl={{ span: 16, offset: 4 }}
style={{ textAlign: 'center', marginTop: '40px' }}
>
<h2>Head</h2>
<p>
Text
</p>
<Button
className="button--center"
size="large"
type="primary"
onClick={() => this.setState({ createCategory: true })}
>
Los geht's
<Icon type="right" />
</Button>
</Col>
</Row>
) : (
<div>
<div className="page-title">
<h1>Content Creator</h1>
<p>
Text
</p>
</div>
<Row gutter={40}>
<Col xs={24}>
<div className="shadow-wrapper">
<DragDropContext
onDragEnd={this.onDragEnd}
>
<Droppable droppableId="droppable">
{(provided, snapshot) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{stateCategories.map((category, index) => (
<Draggable key={category._id} draggableId={category._id} index={index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
>
<Card className="card--list-view">
<div>
<div className="card__title">
<span {...provided.dragHandleProps}>
<Icon
component={DragIndicator}
style={{
paddingRight: '20px',
paddingTop: '6px',
}}
/>
</span>
<a href={`/content-creator/kategorie/${category._id}`}>
{category.title}
</a>
</div>
<div className="card__edit">
<span>
<a
href={`/content-creator/neuen-artikel-anlegen?id=${category._id}`}
onClick={() => FlowRouter.go(
'/content-creator/neuen-artikel-anlegen',
{},
{ id: category._id },
)
}
>
<Icon type="folder-add" />
{' Artikel hinzufügen'}
</a>
</span>
<Text
label="Umbenennen der Kategorie"
required
message="Bitte tragen Sie einen Kategorietitel ein."
initialValue={category.title}
render={(
<span>
<Icon
style={{
marginRight: 5,
}}
type="edit"
/>
Umbenennen
</span>
)}
onValid={(result) => {
Meteor.call(
'post.category.edit',
category._id,
{ title: result },
(e) => {
if (e) {
console.log(e);
message.error('Bei dieser Aktion ist ein Fehler aufgetreten');
} else {
message.success('Kategorie Titel erfolgreich erstellt');
}
},
);
}}
/>
<Popover
content={(
<div className="manager-dashboard">
<div
className="page__actions"
style={{ marginBottom: 0, marginTop: 0 }}
>
<Button
type="danger"
onClick={() => this.handleDeletePopoverVisibleChange(false, category._id)
}
>
<Icon type="close" />
{' Abbrechen'}
</Button>
<Button
type="primary"
style={{ marginLeft: '10px' }}
onClick={event => this.handleDelete(event, category._id)}
>
{'Löschen '}
<Icon type="delete" />
</Button>
</div>
</div>
)}
title="Diese Kategorie wirklich löschen?"
trigger="click"
visible={deletePopoverVisible[category._id]}
onVisibleChange={change => this.handleDeletePopoverVisibleChange(change, category._id)
}
>
<Icon type="delete" />
{' Löschen'}
</Popover>
<Switch
style={{ float: 'right' }}
defaultChecked={category.state}
onChange={checked => this.handleCategoryState(category._id, checked)}
checkedChildren="Öffentlich"
unCheckedChildren="Entwurf"
/>
</div>
</div>
</Card>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
{Role.hasPermission('product.category.create') && (
<Card
className="card--list-view add-new-card"
onClick={() => this.setState({ createCategory: true })}
>
<div className="card__title">
<a>+ Neue Kategorie hinzufügen</a>
</div>
</Card>
)}
</div>
</Col>
</Row>
</div>
)}
{createCategory && (
<CreatePostCategory
ref={(form) => {
this.createCategoryForm = form;
}}
visible={createCategory}
onCancel={() => this.setState({ createCategory: false })}
onCreate={this.handleCreateCategory}
/>
)}
</Col>
<Col xs={24} sm={12} lg={8} xxl={6}>
<Preview type="categories" />
</Col>
</Row>
</Col>
);
}
return content;
}
}
export default withTracker(() => {
const user = Meteor.user();
const handleCategories = Meteor.subscribe('posts.categories.all', {
query: { workspace: user.profile.workspace },
sort: { index: 1, title: 1 },
fields: {
title: 1, state: 1, index: 1, workspace: 1,
},
});
const ready = handleCategories.ready();
let categories = null;
if (ready) {
categories = PostCategories.find(
{ workspace: user.profile.workspace },
{
sort: { index: 1, title: 1 },
fields: {
title: 1, state: 1, index: 1, workspace: 1,
},
},
).fetch();
}
return {
user,
ready,
categories,
};
}, Categories);
I am completly clueless what is going wrong, maybe somebody could help me out
React components are functions, and this error message comes about because you are passing in an object rather than a function.
That may be enough for you to find the problem now. It is helpful for us if you can do some narrowing down of the problem, rather than dumping a large amount of code - it becomes too expensive (time consuming) for us to help you if we have to pore through hundreds of lines of code.