为什么儿童部分的州会不断清理?

时间:2018-03-17 22:30:11

标签: javascript reactjs

我有多层React组件,用于从音乐服务API获取嵌入,包括命中API以填充嵌入的高阶组件。我的问题是我的最低级别的子组件不会改变状态。我基本上希望填充的嵌入(最低级别组件)显示专辑封面,在单击它后显示消失(显示iframe),并且其状态保持稳定,除非道具更高的任何变化(到此组件显示时,那里应该没有其他状态的变化,除了焦点更高)。这是代码:

父:

return (
            /*...*/
                <Embed
                    embed={this.props.attributes.embed}
                    cb={updateEmbed}
                />
            /*...*/

第一个孩子(上图):

render() {
        const {embed, className, cb} = this.props;
        const {error, errorType} = this.state;
        const WithAPIEmbed = withAPI( Embed );

        /*...*/

        return <WithAPIEmbed
            embed={embed[0]}
            className={className}
            cb={cb}
        />;
        /*...*/

withAPI:

/*...*/
        componentWillMount() {
            this.setState( {fetching: true} );
        }

        componentDidMount() {
            const {embed} = this.props;

            if ( ! embed.loaded ) {
                this.fetchData();
            } else {
                this.setState( {
                    fetching: false,
                    error: false,
                } );
            }
        }

        fetchData() {
           /*... some API stuff, which calls the callback in the top level parent (cb()) setting the embed prop when the promise resolves -- this works just fine ...*/ 
        }

        render() {
            const {embed, className} = this.props;
            const {fetching, error, errorType} = this.state;

            if ( fetching ) {
                /* Return some spinner/placeholder stuff */
            }

            if ( error ) {
                /* Return some error stuff */
            }

            return (
                <WrappedComponent
                    {...this.props}
                    embed={embed}
                />
            )
        }

最后,我感兴趣的是最后一个孩子:

constructor() {
        super( ...arguments );
        this.state = {
            showCover: true,
        };
    }

    render() {
        const {embed, setFocus, className} = this.props;
        const {showCover} = this.state;

        if ( showCover ) {
            return [
                <div key="cover-image" className={classnames( className )}>
                    <figure className='cover-art'>
                        <img src={embed.coverArt} alt={__( 'Embed cover image' )}/>
                        <i onClick={() => {
                            this.setState( {showCover: false,} );
                        }}>{icon}</i> // <-- Play icon referenced below.
                    </figure>
                </div>,
            ]
        }

        return [
            <div key="embed" className={className}>
                    <EmbedSandbox
                        html={iframeHtml}
                        type={embed.embedType}
                        onFocus={() => setFocus()}
                    />
            </div>,
        ];
    }

我的问题是点击播放图标应该清除专辑封面并显示嵌入的iframe,但即使点击正在注册,状态也不会改变(或者会改变然后再改变)。我相信它是因为更高级别的组件正在安装/卸载并以其默认状态重新实例化该组件。我可以把这个状态移到树上或使用像Flux这样的东西,但我真的觉得我不应该这样做,而且我在这里缺少一些基本的东西。

1 个答案:

答案 0 :(得分:1)

问题是const WithAPIEmbed = withAPI( Embed );在render方法中。这将在每个渲染上创建一个新的WithAPIEmbed对象,该对象将被重新安装,清除下面的任何状态。将它从类定义中提取出来可以使它稳定并解决问题。