未捕获的类型错误:无法读取 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