请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

expected a string or a class/function but got: undefined

type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `TopicDetail`.
    in TopicDetail (created by inject-TopicDetail)
    in inject-TopicDetail (created by WithStyles(inject-TopicDetail))
    in WithStyles(inject-TopicDetail) (created by Route)
    in Route (created by _default)
    in _default (created by App)
    in App (created by Main)
    in Main
    in MuiThemeProvider
    in Router (created by BrowserRouter)
    in BrowserRouter
    in Provider
    in AppContainer

 发生原因一般是引用了无效的组件,如果组件确实正确,看下引用的组件是否正常导出:(export default)


但是并没有找到哪里出了问题

TopicDetail 源代码:

import React from 'react'
import PropTypes from 'prop-types'
import marked from 'marked'
import Helmet from 'react-helmet'
import {
inject,
observer,
} from 'mobx-react'
import green from '@material-ui/core/colors/green'
import { withStyles } from '@material-ui/core/styles'
import Paper from '@material-ui/core/Paper'
import { CircularProgress } from '@material-ui/core/CircularProgress'
import Container from '../layout/container'
import { topicDetailStyle } from './styles'
import Reply from './reply'
import TopicStore from '../../store/topic-store'

@inject((stores) => {
  return {
    topicStore: stores.topicStore,
}
}) @observer
class TopicDetail extends React.Component {
  componentDidMount() {
    const id = this.getTopicId()
    this.props.topicStore.getTopicDetail(id)
  }

  getTopicId() {
    return this.props.match.params.id
  }

  render() {
    const {
      classes,
    } = this.props
    const id = this.getTopicId() // 通过react-router生成的match对象获取url的params参数
    const topic = this.props.topicStore.detailMap[id]
    // const topic = this.props.topicStore.topics[1]
    if (!topic) { // topic 不存在加载 loading
      return (
        <Container>
          <section className={classes.loadingContainer}>
            <CircularProgress style={{ color: green[500] }} size={100} />
          </section>
        </Container>
      )
    }

    // 把内容放到 p 标签下,但是是直接塞入 html,不转义html标签
    return [
      <Container>
        <Helmet>
          <title>{topic.title}</title>
        </Helmet>
        <header className={classes.header}>
          <h3>{topic.title}</h3>
        </header>
        <section className={classes.body}>
          <p dangerouslySetInnerHTML={{ __html: marked(topic.content) }} />  {/* eslint-disable-line */}
        </section>
      </Container>,

      <Paper elevation={4} className={classes.replies}>
        <header className={classes.replyHeader}>
          <span>{`${topic.reply_count} 回复`}</span>
          <span>{`最新回复 ${topic.last_reply_at}`}</span>
        </header>
        <section>
        {
          topic.replies.map(reply => <Reply reply={reply} key={reply.id} />)
        }
        </section>
      </Paper>,
      ]
    }
  }

TopicDetail.propTypes = {
  topicStore: PropTypes.instanceOf(TopicStore),
  classes: PropTypes.object.isRequired,
  match: PropTypes.object.isRequired,
}

export default withStyles(topicDetailStyle)(TopicDetail)


topic stre 源代码

import {
observable,
toJS,
computed,
action,
extendObservable,
} from 'mobx'
import { topicSchema } from '../utils/variable-define'
import { get } from '../utils/http'

const createTopic = (topic) => {
return Object.assign({}, topicSchema, topic) // 返回所有字段都有定义的topic对象
}

/**
 * 为了以后扩展更加容易,创建一个类,让每个话题都放到这个类中
 * 即变成类的实例,更好的控制话题
 * 让数据使用 mobx 具有的特性
 */
export class Topic { // 创建 topic 的时候就是所有有定义的字段都添加 observable 属性并附加this
constructor(data) {
extendObservable(this, data) // 把数据直接扩展到 this 上并使用 observeable
}

@observable syncing = false // 是否异步操作请求数据,在组件中反应正在加载的操作
}

class TopicStore {
@observable topics

@observable details // 数组

@observable syncing // 是否正在处理数据请求

// constructor({ syncing, topics, details } = { syncing: false, topics: [], details: [] }) {
constructor({ syncing = false, topics = [], details = [] } = {}) { // 整个对象默认等于 空对象
// 初始化数据,设置默认值
this.syncing = syncing
this.topics = topics.map(topic => new Topic(createTopic(topic))) // 数组使用map
this.details = details.map(topic => new Topic(createTopic(topic))) // 数组使用map
}
/**
   * 上面是 topic 的定义
   * 下面获取 topic 数据
   */

addTopic(topic) { // 往 topics 里加入新的 topic 对象
this.topics.push(new Topic(createTopic(topic)))
}

@computed get detailMap() { // 方便获取某个 id 下的 detail
return this.details.reduce((result, detail) => {
result[detail.id] = detail // eslint-disable-line
return result
}, {})
}

@action fetchTopics(tab) {
this.syncing = true // 开始请求数据之前设置为 true 表示正在异步获取数据
this.topics = [] // 获取之前先清空
return new Promise((resolve, reject) => {
get('/topics', {
mdrender: false, // markdown 字符串是否转义成 html 字符串,不转义还可以继续编辑 markdown
tab,
}).then((resp) => {
if (resp.success) { // 把拿到的所有 topic 都放到 this.topics 里
resp.data.forEach((topic) => {
this.addTopic(topic)
})
resolve() // 数据获取成功
} else {
reject() // 数据获取失败
}
this.syncing = false // 数据获取结束
}).catch((err) => { // 出现任何异常
reject(err)
this.syncing = false // 出现异常数据获取结束
})
})
}

@action getTopicDetail(id) {
return new Promise((resolve, reject) => {
if (this.detailMap[id]) { // 有数据,即已经获取过该id的详情数据
resolve(this.detailMap[id])
} else { // 没有就获取
get(`/topic/${id}`, {
mdrender: false, // 不要转化 markdown 格式
}).then((resp) => {
if (resp.success) {
const topic = new Topic(createTopic(resp.data)) // 新建一个 topic 对象
this.details.push(topic) // 获取的数据放入 details 数组中
resolve(topic) // 就可以很方便的根据id去 detailMap 获取有详情的话题对象
} else {
reject()
}
}).catch(reject)
}
})
}

toJson() {
return {
topics: toJS(this.topics),
syncing: this.syncing,
details: toJS(this.details),
}
}
}

export default TopicStore


正在回答 回答被采纳积分+3

1回答

提问者 慕侠3851047 2018-07-16 11:51:59

出错为模块化组件:

使用     module.export    改写 模块导出方式  

const TopicDetails = withStyles(topicDetailStyle)(TopicDetail)

module.export = TopicDetails

在 router.jsx 修改路由

import { TopicDetail } from '../views/topic-detail/index.jsx'
...
<Route path="/detail/:id" component={TopicDetail} key="detail" />,

//img1.sycdn.imooc.com//szimg/5b4c15ca000146ee13380819.jpg

发现页面加载并没有访问 TopicDetails 组件,在 TopicDetails 组件 componentDidMount 中增加

console.log("componentDidMount运行\n,getTopicId:", this.getTopicId())

并没有运行,为什么组件没有加载呢

0 回复 有任何疑惑可以回复我~
  • Jokcy #1
    应该是module.exports,而且你完全可以用export default
    回复 有任何疑惑可以回复我~ 2018-07-16 13:59:14
  • 提问者 慕侠3851047 回复 Jokcy #2
    老师使用 export default 会报错 > type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
    Check the render method of `TopicDetail`.
    回复 有任何疑惑可以回复我~ 2018-07-16 15:02:01
  • Jokcy 回复 提问者 慕侠3851047 #3
    你把你export的内容打印一下看看
    回复 有任何疑惑可以回复我~ 2018-07-17 11:28:04
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信