繁体   English   中英

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

[英]How to reset state on props change in an already mounted component?

我有一个<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;

起初我只在componentDidMount()方法内调用preloadImages() 这对我用它渲染的第一篇文章完美无瑕。

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

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

我决定从UNSAFE_componentWillReceiveProps()方法中调用相同的preloadImages()函数。 基本上它将我的state重置为初始条件,因此<Spinner/>显示,博客文章仅在所有图像都已加载时呈现。

它按预期工作,但由于方法的名称包含单词“UNSAFE”,我很好奇是否有更好的方法。 尽管我认为我内心并没有做任何“不安全”的事情。 我的组件仍然尊重它的props ,并且无论如何都不会改变它们。 它刚被重置为其初始行为。

RECAP:我需要的是一种方法将已经安装的组件重置为其初始state并调用preloadImages()方法(在更新周期内),因此它将按照新安装的方式运行。 有没有更好的方法或我做的很好? 谢谢。

我会停止使用componentWillReceiveProps()资源 )。 如果您不想要刺耳的效果,可以避免它的一种方法是从<BlogPost/>的父级加载信息,并且只在加载信息<BlogPost/>作为道具传递到<BlogPost/>

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

不推荐使用componentWillReceiveProps ,它应该替换为getDerivedStateFromPropscomponentDidUpdate ,具体取决于具体情况。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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