在reactjs中使用this.setstate遇到问题。我正在使用lumen搜索数据库中的某些记录。一切正常,但经过一段时间的搜索,我遇到了此错误:
NotFoundError:无法在“节点”上执行“ removeChild”:要删除的节点不是该节点的子节点。
浏览器突出显示了我正在更新应用程序状态的部分以及错误所在的位置。我猜想原因是setstate已达到其最大限制。
下面是我的源代码。
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch, Link} from 'react-router-dom';
import axios from 'axios';
import { TheProject } from './TheProject';
import { Footer } from '../Footer';
import { Nav } from '../Nav';
import { Header } from '../Header';
const get_url = window.location.href;
var last_part = get_url.substring(get_url.lastIndexOf("/") + 1, get_url.length);
let paginations = [];
let search_paginations = [];
let the_search_result = [];
export class Projects extends Component {
constructor(props) {
super(props);
this.state = {
search_result: '',
search_paginate_result: '',
search_project: '',
search_category: '',
current_page:last_part,
per_page:50,
counter:0,
paginate_projects: '',
all_projects: '',
cur_email: localStorage.getItem('cur_email'),
project_added: localStorage.getItem('project_added'),
project_updated: localStorage.getItem('project_updated'),
project_uploaded: localStorage.getItem('project_uploaded'),
project_deleted: localStorage.getItem('project_deleted'),
isUser: false,
isLoaded: false,
isSearched: false
}
this.searchProject = this.searchProject.bind(this);
this.getInput = this.getInput.bind(this);
this.onCategoryChange = this.onCategoryChange.bind(this);
}
componentWillReceiveProps(the_props) {
if(the_props.navigation.state.params.updated) {
this.setState({
isLoaded: false
});
this.fetchData();
}
}
async componentDidMount() {
this.fetchData();
}
fetchData = () => {
axios.all( [
axios.get('http://localhost:8000/the-projects/'+last_part),
axios.get('http://localhost:8000/all-projects')
])
.then( ([paginate,all]) => {
this.setState({
paginate_projects: paginate.data,
all_projects: all.data,
isUser: true,
counter:1,
isLoaded: true,
});
if(this.state.counter == 0) {
window.location.reload(true);
}
})
.catch( (error) => {
console.log(error);
});
}
getInput = (event) => {
this.setState({
[event.target.name] : [event.target.value]
});
}
onCategoryChange = (event) => {
this.setState({
[event.target.name] : [event.target.value]
});
}
validateForm = (item,category) => {
if(item == "" || category == "") {
return 1;
} else {
return 0;
}
}
highlightTextx = (element, word) => {
var text = element.innerHTML;
element.innerHTML = text.replace(/feeding/gi, "<mark>feeding</mark>");
}
highlightText = (element, phrase, allOccurrences, caseSensitive) => {
var modifiers = (allOccurrences ? 'g' : '') + (caseSensitive ? '' : 'i');
var text = element.innerHTML;
element.innerHTML = text.replace(new RegExp(phrase, modifiers), function(match){
return "<mark>" + match + '</mark>';
});
}
highBtn = () => {
var el = document.getElementById('container');
this.highlightText(el, 'feeding', true, false);
}
highlightIt = (div,word) => {
var el = document.getElementById(div);
this.highlightText(el, word, true, false);
}
searchProject = (event) => {
event.preventDefault();
const status = document.getElementById('search_status');
const searchBtn = document.getElementById('searchBtn');
let search_item = this.state.search_project;
let search_category = this.state.search_category;
let validateForm = this.validateForm(search_item,search_category);
if(validateForm == 1) {
status.innerHTML = "<p style='color:red;font-size:20px' align='center'> Kindly fill both fields. </p>";
return false;
} else {
status.innerHTML = "<p style='color:green;font-size:20px' align='center'> Please wait... </p>";
searchBtn.setAttribute('disabled','disabled');
searchBtn.innerHTML = 'Please wait...';
let data = "search_project="+search_item+"&search_category="+search_category;
axios({
method: 'post',
url: 'http://localhost:8000/search-project',
data: data,
header: {
'Accept-Control-Allow-Origin': '*',
'Content-type': 'application/json'
}
}).then(response => {
if(response.status == 200 && response.statusText == 'OK') {
searchBtn.removeAttribute('disabled');
searchBtn.innerHTML = "<i class='fa fa-search'></i> Search";
if(response.data == "no_match") {
status.innerHTML = "<h3 style='color:red;font-size:20px' align='center'>No match found for <b>"+search_item+"</b> </h3>";
} else {
//This.setstate is where the problem lies. After searching for like 4 - 5 times, it throws up an error and displays this
this.setState({
search_result: response.data,
search_project: '',
search_category: '',
isSearched: true
});
the_search_result = response.data;
let count_result = this.state.search_result.length;
document.getElementById("search_project").value="";
document.getElementById("search_category").value="";
if(count_result == 1) {
status.innerHTML = "<h3 style='color:green;font-size:30px' align='center'>Search result for <b>"+search_item+"</b> </h3> <h4 style='color:green' align='center'> "+count_result+" match found</h4>";
} else if(count_result > 1) {
status.innerHTML = "<h3 style='color:green;font-size:30px' align='center'>Search result for <b>"+search_item+"</b> </h3> <h4 style='color:green' align='center'> "+count_result+" matches found</h4>";
}
localStorage.setItem('the_search_item',search_item);
this.highlightIt('the_search_display',localStorage.getItem('the_search_item'));
}
} else {
status.innerHTML = "<p style='color:red'> Invalid request. </p>";
}
}).
catch( (error) => {
searchBtn.removeAttribute('disabled');
searchBtn.innerHTML = "<i class='fa fa-search'></i> Search";
status.innerHTML = "<p style='color:red'> Invalid request. </p>";
});
}
}
render() {
let project_added_text = null;
let project_updated_text = null;
let project_deleted_text = null;
let project_uploaded_text = null;
let display_projects = null;
let display_search_projects = null;
let display_projects_div = document.getElementById("all_projects_div");
let search_projects_div = document.getElementById("search_result_div");
let project_num = document.getElementById("project_num");
//display all projects in component
if(this.state.all_projects.length > 0) {
display_projects_div.display = "block";
search_projects_div.display = "none";
project_num.innerHTML = this.state.all_projects.length;
display_projects = this.state.paginate_projects.map( (project,index) => {
let serial_no = this.state.per_page*(this.state.current_page-1);
return <TheProject key={index} serial={index+1} project_id={project.id} title={project.title} researcher={project.researcher} matric={project.matric} supervisor={project.supervisor} year={project.year} degree={project.degree} field={project.field} keywords={project.keywords} abstract={project.abstract} path={project.path} added_on={project.created_at} updated_on={project.updated_at}/>
});
}
//display search result
if(this.state.search_result.length > 0 && this.state.isSearched) {
display_projects_div.style.display = "none";
search_projects_div.style.display = "block";
project_num.innerHTML = this.state.search_result.length;
console.log(the_search_result);
display_search_projects = this.state.search_result.map( (project,index) => {
return <TheProject key={index} serial={index+1} project_id={project.id} title={project.title} researcher={project.researcher} matric={project.matric} supervisor={project.supervisor} year={project.year} degree={project.degree} field={project.field} keywords={project.keywords} abstract={project.abstract} path={project.path} added_on={project.created_at} updated_on={project.updated_at}/>
});
}
if(this.state.project_added) {
project_added_text = "Research was successfully added";
localStorage.removeItem('project_added');
} if(this.state.project_deleted) {
project_deleted_text = "Research was successfully deleted";
localStorage.removeItem('project_deleted');
} if(this.state.project_updated) {
project_updated_text = "Research was successfully updated";
localStorage.removeItem('project_updated');
} if(this.state.project_uploaded) {
if(this.state.project_uploaded == 1) {
project_uploaded_text = this.state.project_uploaded+ " research was successfully uploaded";
} else if(this.state.project_uploaded > 1) {
project_uploaded_text = this.state.project_uploaded+ " researches were successfully uploaded";
}
localStorage.removeItem('project_uploaded');
}
let count_pages = Math.ceil(this.state.all_projects.length/this.state.per_page);
for(var i=1;i<=count_pages;i++) {
paginations[i] = i+" ";
}
let count_search_pages = Math.ceil(this.state.search_result.length/this.state.per_page);
for(var i=1;i<=count_search_pages;i++) {
search_paginations[i] = i+" ";
}
return (
<div>
<div id="container" className="effect aside-float aside-bright mainnav-lg">
<Header/>
<div className="boxed">
<div id="content-container">
<div id="page-content">
<div className="row">
<div className="col-xs-12">
{/* <div id="title">Highlight this blah blah HiGhLiGhT THIS blah</div>
<button id="clickme" type="button" onClick={() => this.highBtn()}>Click to highlight text</button> */}
<div className="tabs-container">
<div className="tab-content">
<div align="center">
<Link to="/add-research" className="btn btn-info"><i className="ion-plus-circled"></i> Add New Research </Link>
<Link to="/upload-research" className="btn btn-mint"><i className="fa fa-upload"></i> Upload Researches </Link>
</div> <br/>
<div className="tab-content">
<div align="left">
<p className="text-success"> {project_added_text} </p>
<p className="text-success"> {project_updated_text} </p>
<p className="text-success"> {project_uploaded_text} </p>
<p className="text-success"> {project_deleted_text} </p>
</div>
<div className="panel">
<div className="panel-heading">
<h3 className="panel-title"><i className="fa fa-bars"></i> All Researches <span className="badge badge-success" id="project_num"></span></h3>
</div>
</div>
<br/>
<form className="form-horizontal" method="post" onSubmit={event => this.searchProject(event)}>
<div className="col-md-12 col-sm-12 col-xs-12">
<div className="col-md-6 col-sm-6 col-xs-12">
<input type='text' className="form-control" name='search_project' placeholder='What are you looking for?' id='search_project' onChange={event => this.getInput(event)}/>
</div>
<div className="col-md-3 col-sm-3 col-xs-12">
<select className="form-control" name="search_category" id="search_category" onChange={event => this.onCategoryChange(event)}>
<option value=""> -- Select category --</option>
<option value="title"> Title </option>
<option value="researcher"> Name of researcher </option>
<option value="matric"> Matric number </option>
<option value="supervisor"> Supervisor </option>
<option value="year"> Publication year </option>
<option value="degree"> Degree </option>
<option value="field"> Field </option>
<option value="keywords"> Keywords </option>
<option value="abstract"> Abstract </option>
</select>
</div>
<div className="col-md-3 col-sm-3 col-xs-12">
<button className="btn btn-mint" type="submit" id="searchBtn"><i className="ion-search"></i> Search </button>
</div>
</div>
</form>
<div style={{clear:'both'}}></div>
<br/><div className="table-responsive">
<p id='search_status'></p>
<br/>
<div id="all_projects_div">
{!this.state.isLoaded ?
<h2 align="center">
Please wait...
</h2> :
<div>
<table className="table table-striped table-bordered" style={{cellSpacing:0,width:'100%', border:'1px solid #ccc'}}>
<thead>
<tr style={{backgroundColor:'#263238'}}>
<th style={{color:'#fff'}}>S/N</th>
<th style={{color:'#fff'}}>Title</th>
<th style={{color:'#fff'}}>Researcher</th>
<th style={{color:'#fff'}}>Matric no.</th>
<th style={{color:'#fff'}}>Supervisor</th>
<th style={{color:'#fff'}}>Pub. on</th>
<th style={{color:'#fff'}}>Degree</th>
<th style={{color:'#fff'}}>Field</th>
<th style={{color:'#fff'}}>Keywords</th>
<th style={{color:'#fff'}}>Abstract</th>
<th style={{color:'#fff'}}>Action</th>
</tr>
</thead>
<tbody>
{display_projects}
</tbody>
</table>
<div align="center">
Page {last_part} of {count_pages} <br/><br/>
{paginations.map( (paginate) => {
return (
<a href={paginate} style={{fontSize:17,color:'blue'}}> {paginate} </a>
)
})}
</div>
</div>
}
</div>
<div id="search_result_div" style={{display:'none',clear:'both'}}>
{!this.state.isSearched ?
<h2 align="center">
Please wait...
</h2> :
<div>
<table className="table table-striped table-bordered" style={{cellSpacing:0,width:'100%', border:'1px solid #ccc'}}>
<thead>
<tr style={{backgroundColor:'#263238'}}>
<th style={{color:'#fff'}}>S/N</th>
<th style={{color:'#fff'}}>Title</th>
<th style={{color:'#fff'}}>Researcher</th>
<th style={{color:'#fff'}}>Matric no.</th>
<th style={{color:'#fff'}}>Supervisor</th>
<th style={{color:'#fff'}}>Pub. on</th>
<th style={{color:'#fff'}}>Degree</th>
<th style={{color:'#fff'}}>Field</th>
<th style={{color:'#fff'}}>Keywords</th>
<th style={{color:'#fff'}}>Abstract</th>
<th style={{color:'#fff'}}>Action</th>
</tr>
</thead>
<tbody id='the_search_display'>
{display_search_projects }
</tbody>
</table>
</div>
}
</div>
</div>
</div>
<br/>
</div>
</div>
</div>
</div>
</div>
<Nav/>
<div style={{clear:'both'}}> </div>
<Footer/>
<button className="scroll-top btn">
<i className="pci-chevron chevron-up"></i>
</button>
</div>
</div>
</div>
</div>
);
}
}