0

I am using React useReducer and trying to display the information taken from firebase.

     async function reducer(listState, action) {
        switch (action.type) {
            case "load":
            let stateCopy2 = [...listState]; 
        let  result = await firebase.firestore().collection("contractors").doc(action.idList[0].id).get()
        console.log("non promise/ console log 1",result.data())
        return [...stateCopy2, result.data()]
        default:
            throw new Error();
        }
      }
    
      function Thing(props) {      
    
    
    return (
        <div >
              {listState.map((data, index) => (
    <div>
    {data.Bio}
    </div>
))}
    <button onClick={()=>console.log("promise/ console log 2", listState)}>check</button>
    </div>
    )
    }
    export default Thing;

when doing the console.log(listState); at console.log 1 the information shows what it should. Just what it should:

{BIo:"hello"}

at console.log 2 the information it shows is:

Promise {<fulfilled>: Array(2)}

with the original information shown in there.

after the transformation, as listState is the promise it cannot be mapped though.

How would I turn the promise into just the array or not let it appear as this?

Alexander Hemming
  • 753
  • 1
  • 6
  • 28

2 Answers2

1

You can claim an onClick AsyncFunction:

onClick={async () => console.log("promise/ console log 2", await listState)}

Or simply do a console in "then" method:

onClick={listState.then(data => console.log("promise/ console log 2", data))}
HarryLit
  • 26
  • 2
  • the problem is in this area: {listState.map((data, index) => (
    {data.Bio}
    ))} the problem is because this "Promise {: Array(2)}" is not itterable. So when listState become that, the code breaks
    – Alexander Hemming Feb 26 '21 at 01:25
-1

By marking your reducer as async you're making it return a Promise. As such, you'd need to await it to get its value.

I'm a little surprised the listState.map call doesn't blow up on you, but I admit I haven't really looked that closely, and it's not clear from your code where listState comes from in your Thing component.

Having an asynchronous reducer feels like A Bad Idea™ to me, given that a reducer's job is just to update state in response to an action. There are discussions of this elsewhere on stackoverflow that might be helpful.

ray
  • 26,557
  • 5
  • 28
  • 27
  • It seems pretty hard to get information from firebase without doing async await. There is also an await there, which created the promise. But the value is "Promise {: Array(2)} " this makes it so that I cannot map through the array anymore – Alexander Hemming Feb 26 '21 at 01:17
  • I'm not saying you shouldn't do async/await, I'm saying the reducer isn't the place for it. Obviously your data fetching is going to be asynchronous. – ray Feb 26 '21 at 01:17
  • I agree, but would you know how to fix this situation in which I am using it in the reducer? As the await is there but it comes up with "Promise {: Array(2)}" which holds the array of values i want, but is not itterable – Alexander Hemming Feb 26 '21 at 01:20
  • Create a separate async function to do the data fetching and have that function dispatch the result for your reducer to merge in. `load().then(data => dispatch( ... ))`. That way your reducer doesn't have to be asynchronous. – ray Feb 26 '21 at 01:25
  • ok, ill just use useEffect and hope that it doesn't make a promise holding the value but the values itself. I do still need to use promises as the useEffect is already getting the info used in the database search. – Alexander Hemming Feb 26 '21 at 01:30
  • You don't have to hope for a particular behavior. It's deterministic. – ray Feb 26 '21 at 02:14
  • the hope is dependent on you being correct, my hope was in vain as your method did not work. – Alexander Hemming Feb 26 '21 at 13:24
  • If you look at the console logs highlighted, you can see that if your method was of any help then the second console log would be the same as the first one. Instead the second one shows "Promise{:Array(2)}" – Alexander Hemming Feb 26 '21 at 14:11
  • Maybe you misunderstood, or maybe your attempt at implementing it is broken, or maybe you didn't include the relevant parts of your code, but this approach is valid. People do this literally every single day. I'm not going to argue with you. Good luck. – ray Feb 26 '21 at 14:52
  • ah, i didn't remove the async from the start of the reducer when doing the changes, you were correct on that. I guess the main problem is I don't know what you meant by "you need to await it" as I thought that I already had awaited it. Sorry again for the misunderstanding. Though I still think its arrogant to claim your advise is deterministically correct. – Alexander Hemming Feb 26 '21 at 16:54
  • I didn't say my advice is deterministically correct. I meant that the _behavior of javascript_ is deterministic. What I meant by "you need to await it" is that functions declared as `async` [always return a Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#return_value). So if your reducer is `async`, then the return value from it is _a Promise_, not the new state object, and you'd have to await the `reducer()` call's return value to get the actual object. As in `const obj = await newState`. – ray Feb 26 '21 at 17:50
  • ah so i used await in the wrong place, still seems a bit tricky on the exact place to put it as that doesnt seem to effect the delay from the database.get() I am not a programmer and do this in my free time/studied psychology. So I am a bit bad at this. Am trying to undo the negative rating but it doesn't work without an edit. – Alexander Hemming Feb 26 '21 at 20:38
  • You'd have to await it in addition to the database one, not instead of. – ray Feb 26 '21 at 20:48