#javascript #reactjs #d3.js #react-hooks #jquery-isotope
#javascript #reactjs #d3.js #реагирует на перехваты #jquery-isotope
Вопрос:
Я пытаюсь реорганизовать свой существующий код, чтобы использовать перехваты вместо конструкторов, componentDidMount(), componentDidUpdate() . Мой исходный код ниже сделал это просто отлично:
import React from "react";
import '../css/App.css';
import 'jquery/dist/jquery.js';
import Isotope from 'isotope-layout/dist/isotope.pkgd.min.js';
import projectsData from '../data/projectsData';
import Project from './Projects';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
isotope: null,
projectComponents: projectsData.map(project => <Project id={project.id} project={project}/>),
}
}
componentDidMount() {
//load isotope masonry view
const elem = document.querySelector('#visContainer')
if (!this.state.isotope) {
this.setState({
isotope: new Isotope( elem, {
//options
itemSelector: '.gridItem',
layoutMode: 'masonry',
masonry: {
columnWidth: 140,
fitWidth: true
},
getSortData: {
year: '.yearsstart parseFloat',
kind: '.kind'
}
})
});
}
else {
this.state.isotope.reloadItems();
}
}
}
componentDidUpdate() {
if (this.state.isotope) {
this.state.isotope.reloadItems();
this.state.isotope.layout();
}
}
render(){
return (
<body>
<div id='sepLine'>
<div id="visHolder">
<div id="visContainer" style={{position: "relative", width: "840px", height: "1823px"}}>
{this.state.projectComponents}
</div>
</div>
</div>
</body>
);
}
}
export default App
Тем не менее, я пытаюсь изменить это, чтобы использовать библиотеку d3 вместо отображения внешнего компонента (проектов). И сделайте это с помощью перехватов React. То, что у меня есть ниже, отображает данные с использованием d3, но я не могу применить Isotope к идентификатору «visContainer».
Я подозреваю, что это потому, что они происходят в то же время, когда они оба используют useEffect()?:
import React, { useEffect, useState } from "react";
import '../css/App.css';
import 'jquery/dist/jquery.js';
import Isotope from 'isotope-layout/dist/isotope.pkgd.min.js';
import projectsData from '../data/projectsData';
import Project from './Projects';
function App () {
const [isotope, setIsotope] = useState(null);
useEffect(() => {
const projects = d3.select('#visContainer');
projects
.selectAll('.lineDiv')
.data(projectsData)
.enter()
.append('div')
.attr('id', (d,i) => {
return d.title })
.attr('className', d => {
return 'lineDiv gridItem y' d.start.substring(0,4) ' ' d.kind ' ' d.title ' ' d.subtitle.replace(/, /g, ' ');
})
}, []);
useEffect(() => {
const elem = document.querySelector('#visContainer')
setIsotope(new Isotope( elem, {
itemSelector: '.gridItem',
layoutMode: 'masonry',
masonry: {
columnWidth: 140,
fitWidth: true
},
getSortData: {
year: '.yearsstart parseFloat',
kind: '.kind'
}
})
)
},[]);
return (
<body>
<div id='sepLine'>
<div id="visHolder">
<div id="visContainer" style={{position: "relative", width: "840px", height: "1823px"}}>
</div>
</div>
</div>
</body>
);
}
export default App
Любая помощь была бы очень признательна, так как я очень хочу узнать, как далеко я могу продвинуть реагирующие крючки. Заранее спасибо!
Ответ №1:
Я решил это, используя «useEffect» при начальной загрузке для setProjects() с отображением. Затем Isotope получает контроль над ‘#visContainer’ с помощью
document.querySelector('#visContainer')
const App = (props) => {
const [projects, setProjects] = useState(null);
const [isotope, setIsotope] = useState(null);
useEffect(() => {
setProjects(projectsData.map(project => <Project id={project.id} project={project} onClick={filterThisProject}/>))
},[])
useEffect(() => {
const elem = document.querySelector('#visContainer')
setIsotope(new Isotope( elem, {
itemSelector: '.gridItem',
layoutMode: 'masonry',
masonry: {
columnWidth: 140,
fitWidth: true
},
getSortData: {
year: '.start parseFloat',
kind: '.kind'
}
})
)
},[projects]);
return (
<body>
<div id='sepLine'>
<div id="visHolder">
<div id="visContainer" style={{position: "relative", width: "840px", height: "1823px"}} >
{projects}
</div>
</div>
</div>
</body>
);
}
export default App;