react for loop with promise value

Viewed 104

I am struggling with a react promise issue. I think I need to be able to use a state length in a for loop outside the axios .then function. Presently, the code below works when I replace LEN with a numerical value but will not work if I try to use label.length as that value does not exist when the for loop is called. Could anyone advise on the best way to handle this? My code is crude as I'm new to js and react.

    export default function App() {
      const [label, setLabel] = useState([]);
      const handle = useFullScreenHandle();
      const [data, setData] = useState([]);
      const token = fetch('token');
      const headers = {
        'X-CSRF-Token': token,
        'Authorization': 'Basic '+btoa('cred')  
      }
    
      React.useEffect(() => {
        axios
          .get("url", {
            headers: headers
          })
          .then(result => {
            setLabel(Object.keys(result.data).map(key => result.data[key].title));
            setData(Object.keys(result.data).map(key => result.data[key].nid));
            len=label.length
          });
      }, []);
    
    
    console.log(length)
      for (let i = 0; i < **LEN**; i++) {
        i = Number(i)
        lab = label[i];
        dat = data[i];
        var stri = ({id:String(i), category: 'cat', label:"String(i)"+i});
    
        //JSON.stringify({artist: artist, title : title});
        nodes.push (stri);
        var ed = ({id:String(i),source:String(i),target:String(i+1),label:i});
        edges.push(ed);
    
      }
    
      var datada =  ({nodes: nodes, edges:edges});
let element = 
<>
 <Sigma graph={datada}></Sigma>
  return element
</>
}
2 Answers

To prevent datada being unnecessarily recreated and causing unnecessary re-render, create datada with useMemo.

const datada = useMemo(() => {
  const nodes = [];
  const edges = [];

  for (let i = 0; i < label.length; i++) {
    i = Number(i)
    lab = label[i];
    dat = data[i];
    var stri = ({ id: String(i), category: 'cat', label: "String(i)" + i });

    nodes.push(stri);
    var ed = ({ id: String(i), source: String(i), target: String(i + 1), label: i });
    edges.push(ed);
  }

  return { nodes: nodes, edges: edges };
}, [data, label]);

This will guarantee to re-create datada ONLY when data and label are changed.

Also, consider using unstable_batchedUpdates when updating label and data.

import { unstable_batchedUpdates } from "react-dom";

// code omitted
.then(result => {
  unstable_batchUpdates(() => {
    setLabel(Object.keys(result.data).map(key => result.data[key].title));
    setData(Object.keys(result.data).map(key => result.data[key].nid));
  });
});

This will make sure lable and data are updated at the same time, preventing datada being re-created twice.

just get length in the for loop, should not cause any problem.

    export default function App() {
      const [label, setLabel] = useState([]);
      ......
      React.useEffect(() => {
        axios
          .get("url", {
            headers: headers
          })
          .then(result => {
            setLabel(Object.keys(result.data).map(key => result.data[key].title));
            setData(Object.keys(result.data).map(key => result.data[key].nid));
            // len=label.length   <<<< not understand what is this, len is not defined
          });
      }, []);
    
      // use label.lenght directly here
      for (let i = 0; i < label?.length; i++) {
Related