简体   繁体   中英

Proper way to invoke external component's method in React.js

Let's asume that I have three components:

  • <ArticleFinder />
  • <ArticleViewer />
  • <RecentArticleList />

ArticleFinder is a component that fetch article list from server, and shows it. If user click a list item, will show <ArticleViewer />.

ArticleViewer is a component that fetch single article from server and display it.

RecentArticleList is a component that fetch recent 10 articles from server, and shows it. Like ArticleFinder, on user click a list item will show <ArticleViewer />, and if <ArticleViewer /> already mounted, <ArticleViewer /> just reload the article.

ArticleFinder and RecentArticleList components are receiving brief article data like this:

[{ _id: 1, title: 'Helloworld', date: '...' }, { _id: 2, title: 'Farewell!', date: '...' }]

And ArticleViewer will receive more specific data like this:

{ _id: 1, title: 'Helloworld', date: '...', content: '<p>Helloworld!</p>', files: [ ... ], tags: [ ... ] }

This is just for reduce the size of transmission, server will response as minimum data as possible. So for display content and files and others from ArticleViewer, this component must have called somekind of getData method.

Note that those 3 components can exists same time, they have their own range on screen. They can be overwrapped but still they are in the same time, same screen.

So when ArticleViewer mounted, it calls own getData method and display the results, but the problem is that if ArticleViewer is already mounted, click a list from RecentArticleList or ArticleFinder will not trigger getData of ArticleViewer because component didn't unmounted and mounted.

I'm using React Router 4.x with this, so I can redirect the url, but still there is no way to forcely invoke ArticleViewer.getData in ArticleFinder and RecentArticleList.

Someway, I did it with some kind of trick. I just checked the props that receives from React Router(this.props.params) has changed, and then invoke the getData method like this:

componentWillReceiveProps(nextProps, nextState) {
    if(nextProps.location.pathname !== prevPath) {
        prevPath = nextProps.location.pathname;
        this.getArticles(category, search);
    }
}

It's working actually, even if refresh the page, but I don't like it, it's not intuitive, not elegant, at least to me.

Is there a way to solve this problem more elegantly? Especially, somekind of React like(if it exists)?

Code is quite a mess and adding more functionalities makes more ugly and I want to fix this. I know there are no answers in programming but there can be exists readable solution, as I think.

Any advice will very appreciate it. Thanks!

These components seem to share state and functionality between them. You could move this state to the component containing these three components and just pass the article to show into your <ArticleViewer> .

You can use key prop to create a completely new instance of component and will be exactly like you are using the component for the first time.

<ArticleViewer {...yuorProps} key={id_of_article}/>

make sure the id is unique for each article.

Remember that you won't be using the existing component, you end up creating new component.

The React Router v4 way would be to use a custom render function for the Article View route -

<Match pattern="/:articleid" 
    render={({params}) => <ArticleViewer article={params.articleid} />}/>

This will render a new ArticleViewer component on route change.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM