2

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>
       
      )
    }
Uğurcan Uçar
  • 127
  • 1
  • 11

2 Answers2

1

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]
      })));
    });
}, []);
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
0

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);
  });
)
snd
  • 133
  • 6
  • Thanks for reply brother but in useeffect can i use async await or what ? where should i use it – Uğurcan Uçar Jun 08 '21 at 00:22
  • I have updated the code so that it allows you to see better what it looks like. – snd Jun 08 '21 at 00:30
  • Thank you! But its still same brother. i still cant see it. And your code gives me promise but i used async await on my code as yours but still same issue – Uğurcan Uçar Jun 08 '21 at 00:39
  • It would be necessary to adapt my example with your code because I do not know exactly all the code. But normally `async/await` should fix the problem because it does` asynchronous` as well as `synchronous`. – snd Jun 08 '21 at 00:50
  • `Array.prototype.map` callbacks should be synchronous. `fetch` returns a Promise, the promise chain will work in a synchronous callback function. Even if the `async` callback worked you'd still have the issue of state mutation and updates stomping on any previous state update. – Drew Reese Jun 08 '21 at 00:51
  • Can you please console log the value of `result` and `z` to see what it returns? – snd Jun 08 '21 at 00:51
  • @DrewReese is right I forgetten `await Promise.all(...)`. updated the code. – snd Jun 08 '21 at 00:55
  • But don't forget to put a console log of the `result` and `z` values ​​to see if they contain anything – snd Jun 08 '21 at 00:58
  • @Sega I actually copy-paste your code but still same brother i cant understanding it – Uğurcan Uçar Jun 08 '21 at 01:08
  • You can see documentation in [Promise docs Mozilla](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#chaining) – snd Jun 08 '21 at 01:09