javascript - Problem with event listeners not being added again, once React unmounts them
问题描述
I am very new to react, and i decided to build a website using create-react-app for experience. I imported a Gallery component into my code which is causing me some problems. It's basically a Picture Gallery with a filtering and shuffle option which works fine whenever you completely reload the page, yet stops working once you switch between routes (with react-router) inside the webpage itself.
My guess is that the eventListeners are not being added to my buttons once react unmounts them, and I am really unsure as to how to refactor the code at hand, inorder to get it going. I have tried using Hooks but I can't make it work.
How do I refactor the
componentDidMount () {
document.addEventListener('DOMContentLoaded', () => {
window.demo = new Demo(document.getElementById('grid'));
});
}
part of the code in order to get it working without having to reload the entire page?
Homebase.js
import React, { Component } from 'react';
import './Homebase.scss';
import Shuffle from 'shufflejs';
import { Link } from 'react-router-dom';
import Demo from './Homebasescript.js';
class homebase extends Component {
componentDidMount () {
document.addEventListener('DOMContentLoaded', () => {
window.demo = new Demo(document.getElementById('grid'));
});
}
render() {
return (
<section>
<div className="homebase-page">
<div className="container-about">
<div className="row-about">
<div className="homebase-title-container">
<h1 className="homebase-about-title">Townhall <span style={{color: 'rgb(21, 115, 209)'}}>12</span> Base Designs</h1>
<div className="switch-container-th12">
<button className="switch-buttons-th12 switch-to-th9-12">
<div className="switch-buttons-text-12">coming soon</div>
</button>
<button to="/Townhall-10" className="switch-buttons-th12 switch-to-th10-12">
<div className="switch-buttons-text-12">Townhall 10</div>
</button>
<button to="/Townhall-11" className="switch-buttons-th12 switch-to-th11-12">
<div className="switch-buttons-text-12">Townhall 11</div>
</button>
<button to="/Townhall-12" className="switch-buttons-th12 switch-to-th12-12">
<div className="switch-buttons-text-12">Townhall 12</div>
</button>
</div>
</div>
</div>
</div>
<div className="container-about">
<div className="row-about">
<div className="col-4@sm col-3@md">
<div className="filters-group filters-group-left">
<label htmlFor="filters-search-input" className="filter-label filter-color">Search</label>
<input className="textfield filter__search js-shuffle-search" type="search" id="filters-search-input" />
</div>
</div>
</div>
<div className="row-about">
<div className="col-12@sm filters-group-wrap">
<div className="filters-group filters-group-right">
<p className="filter-label filter-color">Filter</p>
<div className="btn-group filter-options">
<button className="btn btn--primary" data-group="war">War</button>
<button className="btn btn--primary" data-group="trophy">Trophy</button>
<button className="btn btn--primary" data-group="farm">Farm</button>
<button className="btn btn--primary" data-group="fun">Fun</button>
<button className="btn btn--primary" data-group="contributors">Contributors</button>
</div>
</div>
<fieldset className="filters-group">
<legend className="filter-label filter-color">Sort</legend>
<div className="btn-group sort-options">
<label className="btn active">
<input type="radio" name="sort-value" value="dom" defaultChecked /> Default </label>
<label className="btn">
<input type="radio" name="sort-value" value="title" /> Title </label>
<label className="btn">
<input type="radio" name="sort-value" value="date-created" /> Date Created </label>
</div>
</fieldset>
</div>
</div>
</div>
</div>
</section>
);
};
};
export default homebase;
and the other file is Homebasescript.js
import Shuffle from 'shufflejs';
class Demo {
constructor(element) {
this.element = element;
this.shuffle = new Shuffle(element, {
itemSelector: '.picture-item',
sizer: element.querySelector('.my-sizer-element'),
});
// Log events.
this.addShuffleEventListeners();
this._activeFilters = [];
this.addFilterButtons();
this.addSorting();
this.addSearchFilter();
}
/**
* Shuffle uses the CustomEvent constructor to dispatch events. You can listen
* for them like you normally would (with jQuery for example).
*/
addShuffleEventListeners() {
this.shuffle.on(Shuffle.EventType.LAYOUT, (data) => {
console.log('layout. data:', data);
});
this.shuffle.on(Shuffle.EventType.REMOVED, (data) => {
console.log('removed. data:', data);
});
}
addFilterButtons() {
const options = document.querySelector('.filter-options');
if (!options) {
return;
}
const filterButtons = Array.from(options.children);
const onClick = this._handleFilterClick.bind(this);
filterButtons.forEach((button) => {
button.addEventListener('click', onClick, false);
});
}
_handleFilterClick(evt) {
const btn = evt.currentTarget;
const isActive = btn.classList.contains('active');
const btnGroup = btn.getAttribute('data-group');
this._removeActiveClassFromChildren(btn.parentNode);
let filterGroup;
if (isActive) {
btn.classList.remove('active');
filterGroup = Shuffle.ALL_ITEMS;
} else {
btn.classList.add('active');
filterGroup = btnGroup;
}
this.shuffle.filter(filterGroup);
}
_removeActiveClassFromChildren(parent) {
const { children } = parent;
for (let i = children.length - 1; i >= 0; i--) {
children[i].classList.remove('active');
}
}
addSorting() {
const buttonGroup = document.querySelector('.sort-options');
if (!buttonGroup) {
return;
}
buttonGroup.addEventListener('change', this._handleSortChange.bind(this));
}
_handleSortChange(evt) {
// Add and remove `active` class from buttons.
const buttons = Array.from(evt.currentTarget.children);
buttons.forEach((button) => {
if (button.querySelector('input').value === evt.target.value) {
button.classList.add('active');
} else {
button.classList.remove('active');
}
});
// Create the sort options to give to Shuffle.
const { value } = evt.target;
let options = {};
function sortByDate(element) {
return element.getAttribute('data-date-created');
}
function sortByTitle(element) {
return element.getAttribute('data-title').toLowerCase();
}
if (value === 'date-created') {
options = {
reverse: true,
by: sortByDate,
};
} else if (value === 'title') {
options = {
by: sortByTitle,
};
}
this.shuffle.sort(options);
}
// Advanced filtering
addSearchFilter() {
const searchInput = document.querySelector('.js-shuffle-search');
if (!searchInput) {
return;
}
searchInput.addEventListener('keyup', this._handleSearchKeyup.bind(this));
}
/**
* Filter the shuffle instance by items with a title that matches the search input.
* @param {Event} evt Event object.
*/
_handleSearchKeyup(evt) {
const searchText = evt.target.value.toLowerCase();
this.shuffle.filter((element, shuffle) => {
// If there is a current filter applied, ignore elements that don't match it.
if (shuffle.group !== Shuffle.ALL_ITEMS) {
// Get the item's groups.
const groups = JSON.parse(element.getAttribute('data-groups'));
const isElementInCurrentGroup = groups.indexOf(shuffle.group) !== -1;
// Only search elements in the current group
if (!isElementInCurrentGroup) {
return false;
}
}
const titleElement = element.querySelector('.picture-item__title');
const titleText = titleElement.textContent.toLowerCase().trim();
return titleText.indexOf(searchText) !== -1;
});
}
}
export default Demo;
I would be extremely thankful for any help, sincei have been stuck on this for days!
解决方案
Like @charlietfl said, DOMContentLoaded
has already occurred on initial page load, and will not be triggered again when you navigate between routes in your SPA.
Try removing the listener:
componentDidMount () {
//document.addEventListener('DOMContentLoaded', () => {
// window.demo = new Demo(document.getElementById('grid'));
//});
window.demo = new Demo(document.getElementById('grid'));
}
推荐阅读
- asp.net-mvc - 应用程序在本地工作,但不能在 azure 上工作
- android - 可以接受位置权限,但返回“用户拒绝地理定位”
- sql - 从头开始安装 Sql Server 的 Powershell 脚本
- python - 如果使用列表推导,为什么函数不会更新列表,但在使用 for 循环时会更新
- git - 强制部分 git cherry-pick?
- r - for循环不创建多个ggplot对象
- vbscript - 在表格顶部显示一列的总计
- docker - 如何使用私有注册表中的基础映像构建 dockerfile?
- ios - 无法通过 Xcode 在 iPhone 上启动 com.myappname
- javascript - 本地 html 站点重定向到在线站点