3

I have the following situation. I am fetching data from the backend and the response is a bunch of objects. I want to iterate into them and in every iteration, I want to push them into my state.

here is how I am getting data from the backend:

     const allBookings = useSelector(getBookings);

      useEffect(() => {
        dispatch(
          fetchBookings.request({
            getAll: true,
          })
        );
      }, [dispatch]);

here is my data:

bookings:{
  0:{id: 294, address: '1585 Charleston Rd, Mountain View, CA, USA', broker:{name:'aaa'}},
  1:{id: 294, address: '1586 Charleston Rd, Mountain View, CA, USA', broker:{name:'bbb'}},
  2:{id: 294, address: '1587 Charleston Rd, Mountain View, CA, USA', broker:{name:'ccc'}}
}

Here where I am trying to set my data in an array, but something goes wrong, please help me to figure out how I can achieve. The final result should be like this:

    [
      {id: 294, address: '1585 Charleston Rd, Mountain View, CA, USA', broker:{name:'aaa'}},
      {id: 294, address: '1586 Charleston Rd, Mountain View, CA, USA', broker:{name:'bbb'}},
      {id: 294, address: '1587 Charleston Rd, Mountain View, CA, USA', broker:{name:'ccc'}}
    ]
     if (!allBookings) return null;

      const book = allBookings.bookings;
      const [books, setBooks] = useState([]);
      useEffect(() => {
        if (book) {
          const x = Object.entries(book);
          setBooks(x);
        }
      }, [book]);

    console.log('books===>', books);

here is my code in sandbox

1
  • Since you already have allBookings why add the same entries in local state ? You can use the allBookings directly. Additionally you cannot use hooks conditionally, meaning that you cannot have a branch like if (..) return null; and then add a useXXX hook after that line. Commented Dec 28, 2021 at 9:09

5 Answers 5

2

Use functional update to push new entires into your books array:

const x = Object.entries(book);
setBooks(books => [...books, ...x]);

Since you’re always instantiating with an empty array you also don’t need the falsy check, ie you can remove if (books).

Sign up to request clarification or add additional context in comments.

Comments

1

change const x = Object.entries(book); to const x = Object.values(book);

Comments

1

In your useEffect use the store selector var to watch changes ,

also you shouldn't use Object.entries in your case , instead use Object.values ,

Object.entries will get both key and values , and put them as an array for each entry like

[["0",{id: 294, address: '1585 Charleston Rd,...}]]

but Object.values wil only create new array from values ( your objects )

your code should looks like

  const [books, setBooks] = useState([]);
  useEffect(() => {
    if (allBookings.bookings) {
      const entries = Object.values(allBookings.bookings);
      setBooks(entries);
    }
  }, [allBookings]);

Try the below Snippet :

// Get a hook function
const {useState, useEffect } = React;

const Example = ({title}) => {
   let serverObject = {
    bookings:{
      0:{id: 294, address: '1585 Charleston Rd, Mountain View, CA, USA', broker:{name:'aaa'}},
      1:{id: 294, address: '1586 Charleston Rd, Mountain View, CA, USA', broker:{name:'bbb'}},
      2:{id: 294, address: '1587 Charleston Rd, Mountain View, CA, USA', broker:{name:'ccc'}}
    }
  }
  
  const [allBookings, setAllBookings] = useState({});
  
  const [books, setBooks] = useState([]);
  
  setTimeout(()=> { setAllBookings(serverObject)},  2000)
  
  
  useEffect(() => {
    if (allBookings.bookings) {
      const entries = Object.values(allBookings.bookings);
      setBooks(entries);
    }
  }, [allBookings]);
  
  return (
    <div>
      {
         books.map( book => <p> {book.address} </p>)
      }
    </div>
  );
};

// Render it
ReactDOM.render(
  <Example title="Example using Hooks:" />,
  document.getElementById("app")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

<div id="app"></div>

Comments

0

use Object.values instead of Object.entries.

Also, merge new res with the previous res.

const data = Object.entries(book);
setBooks(books => [...books, ...data]);

Comments

0

Never recommended to mutate the state directly.

The recommended approach in later React versions is to use an updater function when modifying states to prevent race conditions:

For Functional Components

const [array,setArray] = useState([]);

Push value at the end:

setArray(oldArray => [...oldArray,newValue] );

Push value at the beginning:

setArray(oldArray => [newValue,...oldArray] );

For Class Components

Push string to end of the array, you do this...

this.setState(prevState => ({
  myArray: [...prevState.myArray, "new value"]
}))

Push string to beginning of the array, you do it like this ...

this.setState(prevState => ({
  myArray: ["new value", ...prevState.myArray]
}))

Push object to end of the array, you do this ...

this.setState(prevState => ({
  myArray: [...prevState.myArray, {"name": "object"}]
}))

Push object to beginning of the array, you do this ....

this.setState(prevState => ({
  myArray: [ {"name": "object"}, ...prevState.myArray]
}))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.