How can i access my array inside of object?

Viewed 69

I have a object and inside of object hava data array. But i cant access it. When i log my object i can see my data inside like that : https://ibb.co/mJfHnhq

But when i try write like objectname.data its show empty array like : https://ibb.co/yNSDb94 How can i call it for access my data. I need send it to component but when i send objectname.data its sending empty array. Thanks for reply!

Its How i fill my object data :

const [myData,setMyData]=useState(DropdownElements); //Dropdown elements holds my url title empty array data for fill  etc.
const [myDatax,setMyDatax]=useState([]);

useEffect(() => {
  myData.map((x, i) => {
      fetch(x.apiUrl)
      .then((z) => z.json())
      .then((result) => {
         myData[i].data = result;
         setMyData(myData);
       });
    });
}, []);

Its where i try use it but when i write x.data i cant see my data

return (
    <div>
           
           {myData.map(x=>{
             console.log('MYDATA',x.data)
             
          
            
             return (
               <MySpecialPicker
               key={x.key}
               placeholder={x.placeholder}
               onChange={change=>onchange(change)}
               datasource={x.data}
               >
    
    
               </MySpecialPicker>
             )
           })}
        </div>
       
      )
    }
2 Answers

Issue

You are mutating your state object. When you enqueue a bunch of state updates within a loop using non-functional updates they all use the state from the render cycle the updates were enqueued in, not the value of any previously updated state.

useEffect(() => {
  myData.map((x, i) => {
      fetch(x.apiUrl)
      .then((z) => z.json())
      .then((result) => {
         myData[i].data = result; // <-- mutation, myData state from previous render
         setMyData(myData);
       });
    });
}, []);

Solution

Use a functional state update to correctly update from the previous state instead of the state that was closed over in callback scope when the effect ran. Use .forEach since you are issuing a side-effect to fetch data, not map to a new array (just yet).

useEffect(() => {
  myData.forEach((x, i) => {
      fetch(x.apiUrl)
      .then((z) => z.json())
      .then((result) => {
         setMyData(myData => myData.map((el, index) => index === i {
           ...el,
           data: result,
         } : el));
       });
    });
}, []);

Or map an array of fetch requests and Promise.all them and update state once.

useEffect(() => {
  Promise.all(myData.map(x => fetch(x.apiUrl).then((z) => z.json())))
    .then(data => {
      setMyData(myData => myData.map((el, i) => ({
        ...el,
        data: data[i]
      })));
    });
}, []);

I think the problem was here :

useEffect(() => {
  myData.map((x, i) => {
      fetch(x.apiUrl)
      .then((z) => z.json())
      .then((result) => {
         myData[i].data = result;
         setMyData(myData);
       });
    });
}, []);

In my opinion it is normal that you do not find data because those are promises you are returning a value before the promise value obtained, I advise you to use ES6 or higher with async / await it more easy.

Somethink like :

await Promise.all(
  myData.map(async(x, i) => {
    const z = await fetch(x.apiUrl);

    const result = z.json(); // this is to be checked

    myData[i].data = result;
    setMyData(myData);
  });
)
Related