React setState in map

Viewed 1821

I'm trying to transform the data get from my database to state~ but It only caught the last data in my database. I guess I didn't use the react hook right, it kept overwrite the previous state, so cause the problem now. I've tried lots of ways, but it still not works. I hope can find someone to help me in here QQ

Here is my code

const [dataSource, setDataSource] = React.useState([]);
React.useEffect(() => {
    orders.map((data, i) =>
      setDataSource([
        ...dataSource,
        {
          key: i,
          id: helpers.leftPad(data.oid, 6, 0),
          name: data.cname,
          totalPrice: data.total_price === null ? 'No data' : data.total_price,
          orderDate: data.order_date,
        },
      ])
    );
  }, []);

orders are the data came from the backend and it looks like

[...
...
744: {oid: 749, cid: 545, cname: "Jerry", order_date: "2018-09-04", …}
745: {oid: 750, cid: 546, cname: "Kevin", order_date: "2018-09-18", …}
...
...]

Thank you guys, it will help me a lot!!

5 Answers

you can also perform this as well.

const [dataSource, setDataSource] = React.useState();
React.useEffect(() => {
    let ordersData = orders.map((data, i) =>
      retunr  {
          key: i,
          id: helpers.leftPad(data.oid, 6, 0),
          name: data.cname,
          totalPrice: data.total_price === null ? 'No data' : data.total_price,
          orderDate: data.order_date,
        },
    );
    setDataSource(ordersData)

  }, []);

When using the spread operator, I believe you use a callback function to get the existing state, like this:

const [data, setData] = useState([]);
const newData = {message: "I am new data."};
setData((existingData) => [...existingData, newData]);

Try this:

setDataSource((existingOrders) => [
    ...existingOrders,
    {
      key: i,
      id: helpers.leftPad(data.oid, 6, 0),
      name: data.cname,
      totalPrice: data.total_price === null ? 'No data' : data.total_price,
      orderDate: data.order_date,
    },
  ])

If you use the useState in this form then you have access to the prevState of your state and you can set the object after each other.

const [dataSource, setDataSource] = React.useState([]);
React.useEffect(() => {
    orders.map((data, i) =>
      setDataSource((prevState) => ([
        ...prevState,
        {
          key: i,
          id: helpers.leftPad(data.oid, 6, 0),
          name: data.cname,
          totalPrice: data.total_price === null ? 'No data' : data.total_price,
          orderDate: data.order_date,
        },
      ]))
    );
  }, []);

Or you can use the Array.push method

const [dataSource, setDataSource] = React.useState([]);
React.useEffect(() => {
    let data = []
    orders.map((data, i) =>
      data.push(
        {
          key: i,
          id: helpers.leftPad(data.oid, 6, 0),
          name: data.cname,
          totalPrice: data.total_price === null ? 'No data' : data.total_price,
          orderDate: data.order_date,
        }
    ));

  setDataSource(data)   
  }, []);

Your state will changed for each time you map the orders. It's better to define an array and push items to it. After that change the state once:

  const [dataSource, setDataSource] = React.useState([]);
  React.useEffect(() => {
    let array = [];
    orders.map((data, i) =>
      array.push(
        {
          key: i,
          id: helpers.leftPad(data.oid, 6, 0),
          name: data.cname,
          totalPrice: data.total_price === null ? 'No data' : data.total_price,
          orderDate: data.order_date,
       })             
    );
    setDataSource(array)
    },
 []);

As you already have guessed it right, you are overwriting the previous state. This is because, you are using "setDataSource([])" within map method. Every time you are mapping the "data" aaray, you are using "setDataSource([])" and hence you finally set last value from "data" array as your state. Use your map function to create a new desired array which contains all orders and after this set state. It will be something like this.

const [dataSource, setDataSource] = React.useState([]);
    React.useEffect(() => {
        const newStateArray = [];
        orders.map((data, i) =>
            newStateArray.push({
            key: i,
            id: helpers.leftPad(data.oid, 6, 0),
            name: data.cname,
            totalPrice: data.total_price === null ? 'No data' : data.total_price,
            orderDate: data.order_date,
            });

        );
        setDataSource(newStateArray);
  
     }, []);
Related