Реагирующие крючки D3 и библиотеки изотопов, владеющие состоянием

#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;