用react-router反应HOC

时间:2018-04-01 20:00:44

标签: javascript reactjs react-router state react-props

我正在尝试重新使用我的一个反应组件,我的BlogPost和EditableBlogPost组件都需要对后端进行提取以获取相同的数据。我喜欢使用更高阶的组件来执行此操作,但我不确定如何使用react-router实现此目的,因为我正在直接路由到这些组件。 HOC没有被触发,我无法在我想要的地方进行获取。理想情况下,路由器会渲染HOC,然后将数据传递给我认为的BlogPost和EditableBlogPost组件吗?

代码:

Home.js

  render () {
    return (
      <Switch>
        <Route
          exact
          path={`${this.props.match.url}/:id`}
          component={BlogPost} // id like to use a HOC here to fetch data and pass it down to the BlogPost but i cant do it from within this file.
        />
        <Route
          exact
          path={`${this.props.match.url}/:id/edit`}
          component={EditableBlogPost} // id like to use a HOC here to fetch the data as well and pass it down.
        />
        <Route
          exact
          path={`${this.props.match.url}/new/post`}
          render={() => {
            return <EditableBlogPost isNew />
          }}
        />
        <BlogSummaryContainer posts={this.state.blogPosts} />
      </Switch>
    )
  }

BlogPost.js

class BlogPost extends Component {
  render () {
    console.log(this.props.match.params.id)
    console.log('this.props', this.props)
    const { classes, title, content } = this.props

    return (
      <Card className={classes.card}>
        <CardMedia
          className={classes.media}
          image='/static/images/cards/contemplative-reptile.jpg'
          title='bang'
        />
        <CardContent>
          <Typography className={classes.title}>{title}</Typography>
          <Typography variant='headline'>{title}</Typography>
          <Typography className={classes.pos}>adjective</Typography>
          <Typography variant='body1'>{content}</Typography>
        </CardContent>
        <CardActions>
          <Button
            size='small'
            component={Link}
            to={`${this.props.match.url}/edit`}
          >
            Edit
          </Button>
        </CardActions>
      </Card>
    )
  }

EditableBlogPost.js

  render () {
    const { classes } = this.props
    console.log(this.state)
return (
   ...other code...
    </CardActions>
    <Divider />
    <Typography variant='headline'>Preview</Typography>
    <CardMedia
      className={classes.media}
      image={this.state.file[0].preview}
      title='bang'
    />
    <CardContent>
      <Typography className={classes.title}>
        {this.state.title || 'Title'} // id like this to use props from HOC 
      </Typography>
      <Typography variant='headline'>
        {this.state.title || 'Title'}
      </Typography>
      <Typography className={classes.pos}>
        {this.state.catchPhrase || 'CatchPhrase'}
      </Typography>
      <Typography variant='body1'>
        {this.state.content || 'Content'}
      </Typography>
    </CardContent>
    //this is where <BlogPost> should be instead of duplicating code.
   ...
)

BlogPostContainer.js(HOC我试图使用)

class BlogPostContainer extends Component {
  constructor () {
    super()
    this.state = { title: '', content: '' }
  }

  componentDidMount () {
    fetch(`/api/posts/${this.props.match.params.id}`)
      .then(res => {
        return res.json()
      })
      .then(blogPost => {
        // console.log('blogPost', blogPost)

        this.setState({
          title: blogPost.title,
          content: blogPost.content
        })
      })
  }

  render () {
    return <BlogPost title={this.state.title} />
  }

如果能够以某种方式向下传递获取数据,我可以删除BlogPost和EditableBlogPost之间共享的大量代码。也许我在这里做了一些根本性的错误,但我不确定最好的方法是做什么,任何帮助都表示赞赏。

1 个答案:

答案 0 :(得分:3)

似乎在HOC实际上存在一些误解。 HOC是接受组件的函数,然后返回组成该组件的新组件。 See this guide for more info.

// HOCs are usually written with `with` at the beginning
function withBlogPostData(WrappedComponent) {
  return class BlogPostContainer extends React.Component {
    constructor() {
      super()
      this.state = { title: "", content: "" }
    }

    componentDidMount() {
      fetch(`/api/posts/${this.props.match.params.id}`)
        .then(res => {
          return res.json()
        })
        .then(blogPost => {
          // console.log('blogPost', blogPost)

          this.setState({
            title: blogPost.title,
            content: blogPost.content,
          })
        })
    }

    render() {
      return <WrappedComponent title={this.state.title} />
    }
  }
}

// Create a new component like so
// This way, BlogPost can access the prop `title` given to it by the HOC
const BlogPostWithData = withBlogPostData(BlogPost)

// Then use it in your routes:
<Route component={BlogPostWithData} />

Also look into render props as a more flexible alternative.