开发者问题收集

未捕获的类型错误:无法读取 React 上的 null 属性“addEventListener”

2018-03-13
2894

我对 react 有一个问题。我会创建 2 个文件:

select.js :

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import reactDOM from 'react-dom';
import Select from 'react-select';
import Media from '../media/media';
import Form from '../fields/form.js';

class Select_galery extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input : ''
    }
    this.handleChange = this.handleChange.bind(this);
    this.state.selectValue = this.props.value ? this.props.value.select : 'true';
  }

  handleChange(event){
  this.setState({selectValue:event.target.value});
}



  render() {
    let url_youtube = this.props.name+'[url]';
    let id_youtube = this.props.id+'[url]';
    let value_youtube = this.props.value ? this.props.value.url : '';
    let name_select = this.props.name+'[select]';
    let name_img = this.props.name+'[image]';
    let id_img = this.props.id+'[image]';
    // let url_img = this.props.url+'[image][url]';
    if(this.state.selectValue == 'true'){
      this.state.input = <Media name={name_img} id={id_img} />;
    }else{
      this.state.input = <div><label htmlFor={id_youtube}>Url Video</label><input id={id_youtube} type='text' name={url_youtube} defaultValue={value_youtube} className="widefat"/></div>;
    }
    return (
      /* NE PAS OUBLIER LE FOR !!!! */
       <label htmlFor={this.props.id}>{this.props.label}
          {this.state.selectValue}
         <select defaultValue={this.state.selectValue}  id={this.props.id} className="widefat" name={name_select} onChange={this.handleChange.bind(this)}>
           <option value="true">Image</option>
           <option value="false">Video</option>
         </select>
        {this.state.input}
       </label>
    );
  }
}
export default Select_galery;

和 Media.js :

import React from 'react';
import './media.scss';

class Media extends React.Component {
    constructor(props) {
        super(props);

        /*
         * Default state.
         * We can set the default state based on given props.
         */
        let hasMedia = false;

        if (props.value) {
            hasMedia = !!props.value.id;
        }

        this.state = {
            hasMedia: hasMedia,
            media: {
                id: props.value ? props.value.id : '',
                url: props.value ? props.value.url : '',
                name: props.value ? props.value.name : ''
            },
        };

        /*
         * Bindings.
         */
        this.addImage = this.addImage.bind(this);
        this.removeImage = this.removeImage.bind(this);
        this.select = this.select.bind(this);

        /*
         * Get a WordPress media frame.
         */
        this.wpframe = wp.media({
            // Define behaviour of the media window.
            // 'post' if related to a WordPress post.
            // 'select' if use outside WordPress post.
            frame: 'select',
            // Allow or not multiple selection.
            multiple: false,
            // The displayed title.
            title: 'Insérer Media',
            // The button behaviour
            button: {
                text: 'Insérer',
                close: true
            },
            // Type of files shown in the library.
            // 'image', 'application' (pdf, doc,...)
            /*library:{
                type: props.type ? props.type : 'image'
            }*/
        });

        // Attach an event on select. Runs when "insert" button is clicked.
        this.wpframe.on('select', this.select);
    }


    /**
     * Handle click on the button and open the WordPress
     * media library modal in order to fetch an image from
     * the media library. The returned "attachment id" value
     * is then set to the hidden input value attribute.
     *
     */
    addImage() {
        /*
         * Open the media modal.
         */
        this.wpframe.open();
    }

    /**
     * Return the selected attachment object.
     */
    select() {
        let selection = this.wpframe.state().get('selection').first(),
            type = selection.get('type'),
            id = selection.get('id'),
            thumbUrl = selection.get('icon'), // Default image url to icon.
            sizes = selection.get('sizes');

        /*
         * We receive a BackboneJs Model instance (selection).
         * Now we need to update the component in order to show the selected
         * thumbnail and populate the hidden field value with the "id" of the attachment.
         */
        if ('image' === type)
        {
            if (typeof sizes.thumbnail !== 'undefined') {
                thumbUrl = sizes.thumbnail.url;
            }
        }

        /*
         * We need to change the state in order
         * to force React to render the component.
         */
        this.setState({
            hasMedia: true,
            media: {
                id: id,
                url: thumbUrl,
                name: selection.get('filename')
            }
        });
    }

    /**
     * Remove the chosen image.
     * This reset the component state and force re-rendering.
     */
    removeImage() {
        this.setState({
            hasMedia: false,
            media: {
                id: '',
                url: '',
                name: ''
            }
        });
    }

    /**
     * Render a label if defined.
     *
     * @returns {*}
     */
    renderHeader() {
        if (this.props.label) {
            return (
                <div className="media-component-header">
                    <h4>{this.props.label}</h4>
                </div>
            );
        }

        return '';
    }

    /**
     * Render the media component footer.
     *
     * @returns {*}
     */
    renderFooter() {
        if (!this.props.info) {
            return '';
        }

        return (
            <div className="media-component-footer">
                <p className="description">{this.props.info}</p>
            </div>
        );
    }

    /**
     * Render the media component.
     * If there is a media, show the media details with a preview,
     * else only display an "Add Image" button.
     *
     * @returns {XML}
     */
    render() {
        if (this.state.hasMedia) {
            return (
                <div ref={(domElem) => { this.domElem = domElem; }} className="media-component">
                    {this.renderHeader()}
                    <div>
                        <div className="media-inner-wrapper">
                            <div className="media-preview">
                                <div className="centered">
                                    <img className="media-thumbnail" alt="Media Thumbnail" src={this.state.media.url}/>
                                </div>
                            </div>
                            <div className="media-tools">
                                <div className="media-infos">
                                    <h4>Nom du fichier</h4>
                                    <p className="media-filename">{this.state.media.name}</p>
                                </div>
                                <div className="media-buttons">
                                    <button type="button"
                                            className="button button-remove"
                                            onClick={this.removeImage}>Supprimer</button>
                                </div>
                            </div>
                        </div>
                        <input type="hidden" name={`${this.props.name}[id]`} value={this.state.media.id}/>
                        <input type="hidden" name={`${this.props.name}[url]`} value={this.state.media.url}/>
                        <input type="hidden" name={`${this.props.name}[name]`} value={this.state.media.name}/>
                    </div>
                    {this.renderFooter()}
                </div>
            );
        }
        return (
            <div className="media-component">
                {this.renderHeader()}
                <button type="button"
                        className="button button-primary"
                        onClick={this.addImage}>Ajouter</button>
                {this.renderFooter()}
            </div>
        );
    }

    /**
     * We update the DOM hidden inputs define into the parent
     * container of our media component.
     *
     * @param prevProps
     * @param prevState
     */
    componentDidUpdate(prevProps, prevState) {
        /*
         * The "this.domElem" property is only defined
         * when we add an image... otherwise it is null.
         *
         * We the user add/attach an image, we need to update the
         * dom hidden inputs next to our component.
         */
        if (this.domElem) {
            let parent = this.domElem.parentElement.parentElement,
                idInput = parent.querySelector('input.image-id'),
                urlInput = parent.querySelector('input.image-url'),
                nameInput = parent.querySelector('input.image-name');

            /*
             * Let's update the value attribute of each DOM hidden input.
             */
            if (idInput || urlInput || nameInput) {
                idInput.setAttribute('value', this.state.media.id);
                urlInput.setAttribute('value', this.state.media.url);
                nameInput.setAttribute('value', this.state.media.name);
            }
        }
    }
}

export default Media;

当我在 Worpdress 中选择图像并保存时,我收到错误消息:

未捕获的 TypeError:无法读取 null 的属性“addEventListener”

当我选择图像时

当我更新我的帖子时

在数据库中

如果你需要更多信息,请问我 ;)

1个回答

media.js 中,我认为您需要将构造函数中绑定下的所有内容添加到 componentDidMount(){.. ,例如:

class Media extends React.Component {
    constructor(props) {
        super(props);

        /*
         * Default state.
         * We can set the default state based on given props.
         */
        let hasMedia = false;

        if (props.value) {
            hasMedia = !!props.value.id;
        }

        this.state = {
            hasMedia: hasMedia,
            media: {
                id: props.value ? props.value.id : '',
                url: props.value ? props.value.url : '',
                name: props.value ? props.value.name : ''
            },
        };

        /*
         * Bindings.
         */
        this.addImage = this.addImage.bind(this);
        this.removeImage = this.removeImage.bind(this);
        this.select = this.select.bind(this);
    }

    componentDidMount(){

        /*
         * Get a WordPress media frame.
         */
        this.wpframe = wp.media({
            // Define behaviour of the media window.
            // 'post' if related to a WordPress post.
            // 'select' if use outside WordPress post.
            frame: 'select',
            // Allow or not multiple selection.
            multiple: false,
            // The displayed title.
            title: 'Insérer Media',
            // The button behaviour
            button: {
                text: 'Insérer',
                close: true
            },
            // Type of files shown in the library.
            // 'image', 'application' (pdf, doc,...)
            /*library:{
                type: props.type ? props.type : 'image'
            }*/
        });

        // Attach an event on select. Runs when "insert" button is clicked.
        this.wpframe.on('select', this.select);
    }
Ted
2018-03-13