Реагировать — Слишком много повторных рендеров при использовании реквизита

#javascript #reactjs #d3.js

Вопрос:

Я занимался проектом, в котором я представляю график на экране. Теперь data государство в пределах App.js передается как опора, а затем вызывает infinite loop error .

Если переменная данных находится в пределах Graph.js файл и используется и определен внутри useState , тогда нет никаких проблем.

Я был немного не уверен, почему это происходит, так как я относительно новичок в реагировании и javascript.

Цель состоит в том, чтобы добавить данные в график, он загружается, затем, когда я изменю данные в App.js файле, страница автоматически загрузится снова с новыми данными.

Любая помощь/совет будут очень признательны 🙂

App.js

 function App() {  const [data, setData] = useState(null)  setData(  {  nodes:[  {name:"Max"},  {name:"George"},  {name:"Jesus"},  {name:"Ben"},  {name:"James"},  {name:"Sam"},  {name:"Sassms"}  ],   edges:[  {source:"Max", target:"George"},  {source:"George", target:"Jesus"},  {source:"Jesus", target:"Max"},  {source:"Jesus", target:"Ben"},  {source:"James", target:"Ben"},  {source:"Sam", target:"Sassms"},  {source:"Sam", target:"Ben"}  ]  })  console.log(data)   return (  lt;Graph colour="Grey" data={data} setData={setData}/gt;  ); }  

Graph.js

 function Graph(props) {  const svgRef = useRef(null);  useEffect(  () =gt; {  let svg = d3.select(svgRef.current)  if(svgRef.current) {// Check that svg element has been rendered  let width = svg.attr("width")  let height = svg.attr("height")   d3.selectAll("svg gt; *").remove();   let edge = svg  .append("g")  .selectAll("line")  .data(props.data.edges)  .enter()  .append("line")  .attr("stroke-width", function(d) {  return 3;  })  .style("stroke", "black")   let node = svg  .append("g")  .selectAll("circle")  .data(props.data.nodes)  .enter()  .append("circle")  .attr("r", 7)  .attr("fill", function(d) {  return "grey";  })  .attr("stroke", "black")  }   }, [props.data])     return (  lt;svg ref={svgRef} id="svgID" width="1000" height="900"gt;lt;/svggt;  )  }  

Ответ №1:

Это потому, что вы обновляете состояние при каждом рендеринге снова и снова. Если вы просто вызовете setData() внутри функции, она вызовет этот сеттер, который вызовет повторный рендеринг и вызовет реакцию на повторный вызов вашей App функции.

Если вы хотите иметь состояние по умолчанию, вы можете сделать это, как показано ниже. Если вы хотите обновить состояние, это должно быть сделано другими действиями, такими как нажатие кнопки, извлечение некоторых данных и т.д.

Ознакомьтесь с демонстрацией ниже, где я добавил кнопку, которая добавляет новое имя в ваш nodes массив:

 function App() {  const [data, setData] = React.useState({  nodes: [  { name: 'Max' },  { name: 'George' },  { name: 'Jesus' },  { name: 'Ben' },  { name: 'James' },  { name: 'Sam' },  { name: 'Sassms' },  ],  edges: [  { source: 'Max', target: 'George' },  { source: 'George', target: 'Jesus' },  { source: 'Jesus', target: 'Max' },  { source: 'Jesus', target: 'Ben' },  { source: 'James', target: 'Ben' },  { source: 'Sam', target: 'Sassms' },  { source: 'Sam', target: 'Ben' },  ],  });   return lt;Graph colour="Grey" data={data} setData={setData} /gt;; }  function Graph(props) {  function addRandomName() {  props.setData({  ...props.data,  nodes: [  ...props.data.nodes,  { name: Math.random().toString(36).slice(2) },  ],  });  }   return (  lt;React.Fragmentgt;  lt;button onClick={addRandomName}gt;Add new namelt;/buttongt;  lt;h2gt;Nameslt;/h2gt;  lt;pgt; {props.data.nodes.map((d) =gt; d.name).join(', ')}  lt;/pgt;  lt;h2gt;Statelt;/h2gt;  lt;pregt;{JSON.stringify(props.data, null, 2)}lt;/pregt;  lt;/React.Fragmentgt;  ); }  ReactDOM.render(  lt;React.StrictModegt;  lt;App /gt;  lt;/React.StrictModegt;,  document.getElementById('root') ); 
 lt;div id="root"gt;lt;/divgt; lt;script src="https://unpkg.com/react/umd/react.production.min.js"gt;lt;/scriptgt; lt;script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"gt;lt;/scriptgt; 

Комментарии:

1. Если бы я хотел затем снова обновить состояние, я бы получил ошибку зацикливания?

2. Как вы хотите обновить состояние? Что могло бы вызвать обновление?

3. Таким образом, в основном состояние будет представлять собой данные графика, то есть узлы и ребра, содержащиеся в нем. Поэтому, если бы я хотел добавить новый узел, я бы сделал setData(//Введите все данные, которые будут отображаться на графике здесь). Итак, если бы я хотел изменить график, следовательно, изменить данные, как, по-вашему, я бы сделал это, используя состояние?

4. Я обновил свой ответ.