如何在已安装的组件中更改道具更改状态?

时间:2019-01-15 16:03:43

标签: javascript reactjs

我有一个<BlogPost>组件,它可能是无状态功能组件,但由于以下原因而成为类有状态组件:

它呈现的blogPost项目(以props接收)的图像中嵌入了html标记的内容,这些图像是我使用marked库进行解析的,并作为博客文章呈现,其段落之间存在图像, h1,h2,h3等

事实是,在将帖子内容呈现给客户端之前,我需要预加载这些图像。我认为,如果您开始阅读一个段落,突然之间它下降了400px,这是一个UX灾难,因为正在加载的图像在阅读时已被装载到DOM。

所以我更喜欢通过渲染<Spinner/>直到我的图像准备好为止。这就是<BlogPost>是具有以下代码的类组件的原因:

class BlogPost extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      pending: true,
      imagesToLoad: 0,
      imagesLoaded: 0
    };
  }

  preloadImages(blogPostMedia) {
    this.setState({
      pending: true,
      imagesToLoad: 0,
      imagesLoaded: 0
    });

    ... some more code ...
    // Get images urls and create <img> elements to force browser download
    // Set pending to false, and imagesToLoad will be = imagedLoaded
  }

  UNSAFE_componentWillReceiveProps(nextProps) {
    if (this.props !== nextProps) {
      this.preloadImages(nextProps.singleBlogPost.media);
    }
  }

  componentDidMount() {
    this.preloadImages(this.props.singleBlogPost.media);
  }

  render() {
    return(
        this.state.pending ?
          <Spinner/>
        : (this.state.imagesLoaded < this.state.imagesToLoad) ?
            <Spinner/>
          : <BlogPostStyledDiv dangerouslySetInnerHTML={getParsedMarkdown(this.props.singleBlogPost.content)}/>
    );
  }
}

export default BlogPost;

起初,我仅在preloadImages()方法内部调用componentDidMount()。这对于我用它渲染的第一篇文章来说是完美的。

但是,一旦我点击了下一个帖子链接;由于我的<BlogPost>组件已经安装,componentDidMount()不会再被调用,并且我将通过单击链接(这是一个单页应用程序)来呈现的所有后续帖子都不会从{ {1}}功能。

所以我需要一种方法来重置preloadImages()并预加载在更新周期内以state接收的新blogPost的图像,因为已经安装了props组件。

我决定从<BlogPost>方法内部调用相同的preloadImages()函数。基本上是将我的UNSAFE_componentWillReceiveProps()重置为初始状态,因此state会立即显示,并且该博客文章仅在所有图像都加载后才会呈现。

它可以按预期工作,但是由于该方法的名称包含单词“ UNSAFE”,我很好奇是否有更好的方法可以做到这一点。即使我认为我没有在其中执行任何“不安全”的操作。我的组件仍然尊重其<Spinner/>,并且无论如何都不会更改它们。它只是被重置为其初始行为。

RECAP:我需要的是一种将已安装的组件重置为其初始props并调用state方法(在更新周期内)的一种方法,这样它就可以像刚安装时一样工作。有没有更好的方法,或者我做的还好吗?谢谢。

2 个答案:

答案 0 :(得分:1)

componentWillReceiveProps已过时,根据情况应替换为getDerivedStateFromPropscomponentDidUpdate

由于preloadImages是异步副作用,因此应同时在componentDidMountcomponentDidUpdate中调用它:

  componentDidMount() {
    this.preloadImages(this.props.singleBlogPost.media);
  }

  componentDidUpdate() {
    this.preloadImages(this.props.singleBlogPost.media);
  }

答案 1 :(得分:1)

我将停止使用componentWillReceiveProps()resource)。如果您不希望受到震荡的影响,可以避免的一种方法是从<BlogPost/>的父级加载信息,并且仅在信息加载一次之后,才将其传递给<BlogPost/>道具。

但是无论如何,您可以使用key来通过从头重新创建组件(resource)来将组件重置为其原始状态。