When I use SSR to render my page, I found that only
Please help me.
import React from 'react';
import PropTypes from 'prop-types';
import ListItem from 'material-ui/List/ListItem';
import ListItemAvatar from 'material-ui/List/ListItemAvatar';
import ListItemText from 'material-ui/List/ListItemText';
import Avatar from 'material-ui/Avatar';
import { withStyles } from 'material-ui/styles';
import { topicPrimaryStyle, topicSecondaryStyle } from './styles';
import { tabs } from '../../util/variable-define';
import cx from 'classnames';
import dateFormat from 'dateformat';
const Primary = ({ classes, topic }) => {
const classNames = cx({
[classes.tab]: true,
[classes.top]: topic.top,
});
return (
<span className={classes.root}>
<span className={classNames}>{topic.top ? 'Top' : tabs[topic.tab]}</span>
<span className={classes.title}>{topic.title}</span>
</span>
);
};
Primary.propTypes = {
classes: PropTypes.object.isRequired,
topic: PropTypes.object.isRequired,
};
const StyledPrimary = withStyles(topicPrimaryStyle)(Primary);
const Secondary = ({ classes, topic }) => (
<span className={classes.root}>
<span className={classes.userName}>{topic.author.loginname}</span>
<span className={classes.count}>
<span className={classes.replyCount}>Reply: {topic.reply_count}</span>
<span>Visiting: {topic.visit_count}</span>
</span>
<span>Date: {dateFormat(topic.create_at, 'yy-mm-dd')}</span>
</span>
);
Secondary.propTypes = {
classes: PropTypes.object.isRequired,
topic: PropTypes.object.isRequired,
};
const StyledSecondary = withStyles(topicSecondaryStyle)(Secondary);
const TopicListItem = ({ onClick, topic }) => (
<ListItem button onClick={onClick}>
<ListItemAvatar>
//Error would happend here
<Avatar src={topic.author.avatar_url} />
</ListItemAvatar>
<ListItemText
primary={<StyledPrimary topic={topic} />}
secondary={<StyledSecondary topic={topic} />}
/>
</ListItem>
);
TopicListItem.propTypes = {
onClick: PropTypes.func.isRequired,
topic: PropTypes.object.isRequired,
};
export default TopicListItem;
import React from 'react';
import { observer, inject } from 'mobx-react';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import Container from '../layout/container';
import Tabs, { Tab } from 'material-ui/Tabs';
import TopicListItem from './list-item';
import List from 'material-ui/List';
import { CircularProgress } from 'material-ui/Progress';
import queryString from 'query-string';
import { tabs } from '../../util/variable-define';
@inject((stores) => {
return {
appState: stores.appState,
topicStore: stores.topicStore,
};
})
@observer
export default class TopicList extends React.Component {
static contextTypes = {
router: PropTypes.object,
};
constructor() {
super();
this.onTabChange = this.onTabChange.bind(this);
this.onListItemClick = this.onListItemClick.bind(this);
}
componentDidMount() {
const tab = this.getTab();
this.props.topicStore.fetchTopics(tab);
}
componentWillReceiveProps(nextProps) {
if (nextProps.location.search !== this.props.location.search) {
this.props.topicStore.fetchTopics(this.getTab(nextProps.location.search));
}
}
onTabChange(e, value) {
this.context.router.history.push({
pathname: '/list',
search: `?tab=${value}`,
});
}
onListItemClick(topic) {
this.context.router.history.push(`/detail/${topic.id}`);
}
getTab(search) {
const searchString = search || this.props.location.search;
const query = queryString.parse(searchString);
return query.tab || 'all';
}
bootstrap() {
const query = queryString.parse(this.props.location.search);
const tab = query.tab || 'all';
const result = this.props.topicStore.fetchTopics(tab).then(() => {
return true;
}).catch(() => {
return false;
});
return result;
}
render() {
const {
topicStore,
} = this.props;
const { syncing } = topicStore;
const topicList = topicStore.topics;
const { createdTopic } = topicStore;
const { user } = this.props.appState;
const tab = this.getTab();
return (
<Container>
<Helmet>
<title>Topic List</title>
</Helmet>
<div>
<Tabs value={tab} onChange={this.onTabChange}>
{
Object.keys(tabs).map(tabKey => (
<Tab key={tabKey} label={tabs[tabKey]} value={tabKey} />
))
}
</Tabs>
</div>
{
createdTopic && createdTopic.length > 0 ?
<List>
{
createdTopic.map((topic) => {
topic = Object.assign({}, topic, {
author: user.info,
});
return (
<TopicListItem key={topic.id} onClick={() => { this.onListItemClick(topic); }} topic={topic} />
);
})
}
</List> :
null
}
<List>
{
topicList.map(topic => (
<TopicListItem
key={topic.id}
onClick={() => { this.onListItemClick(topic); }}
topic={topic}
/>
))
}
</List>
{
syncing ? (
<div style={{ display: 'flex', justifyContent: 'space-around', padding: '40px 0' }}>
<CircularProgress color="secondary" size={100} />
</div>
) : null
}
</Container>
);
}
}
TopicList.wrappedComponent.propTypes = {
appState: PropTypes.object.isRequired,
topicStore: PropTypes.object.isRequired,
};
TopicList.propTypes = {
location: PropTypes.object.isRequired,
};
@gzcisco720: How did you solve your issue?
@riddla Yes, I have solved it.
@gzcisco720: But _how_ did you do it? Can you elaborate on the steps you needed to take?
@riddla Yes, of course, my problem caused by the difference between versions. The element structure has been changed. The
@riddla and also, Sorry for replying you late, hopefully your issues has been fixed already.
I am also having a similar issue. I had a look at your code, and assume that this commit was your solution:
https://github.com/gzcisco720/cnode-proxy/commit/c9f577f16463ec789b82af0fe86fe6aacae1261a
I am not sure this is a sufficient solution though.
I figured out my issue. I had multiple export default withRoot(withStyles(classes)(MyComponent))
.
withRoot
should only be used once the top level page component.
@jakerobers I recently have helped some others fix this issue, I found that similar Error would also be caused by using the wrong way to implement SSR in server.js.
I'm still struggling with this. I don't know how you guys managed to get it working with SSR. Pardon me for saying that I couldn't understand the English used by some people who have solved this problem. Any proper understandable translation of the resolution may help. Thanks in advance.
@vpaul08, I finally found the solution for my problem. But it was closely related to the combination of nextjs and material-ui. Would it help you if I document it here?
@riddla yes please. However I've implemented the feature without mui. I used foundation components instead but knowing what caused this issue may help in future.
@riddla Did you document your solution somewhere? I have the same problem.
@bbigras, @vpaul08, sorry that it took so long for me to respond.
In my case I did strictly follow the structure of the official example over at https://github.com/mui-org/material-ui/tree/master/examples/nextjs to solve the problem:
I had previously tried to wrap the <Component/>
within https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_app.js with recurring components like <Grid/>
and <Typography/>
– which ended up in the Prop className did not match
error message.
I then used a wrapping component directly in the different pages.
@riddla thanks! Did you manage to make the error report thing work?
this thing:
with https://github.com/mui-org/material-ui/tree/master/examples/nextjs I only have an internal error when an error happens.
@bbigras, sorry I did not encounter that error ...
Hi, our project is the same, and the issues is the same too, reference your solution,I did solve the problem,but I don't know why.I reed the doc and the official demos,the official use this structure
<ListItemAvatar>
<Avatar>
<FolderIcon />
</Avatar>
</ListItemAvatar>
so I don't know why we can't use this structure, why this structure will make ssr console error?
Looking forward to your reply, thanks a lot.
Most helpful comment
@vpaul08, I finally found the solution for my problem. But it was closely related to the combination of nextjs and material-ui. Would it help you if I document it here?