3

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!!

hao
  • 197
  • 1
  • 3
  • 11

5 Answers5

3

you can also perform this as well.

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

  }, []);
Hasan ABLAK
  • 21
  • 1
  • 5
  • map function returns a new array so, store that data and use the whole array to set the state. – Dawood Shahid Jul 19 '21 at 08:35
  • It works for me too~~ It's new learning for me, didn't think it can return and setState outside the map! Thanks for answering the question~ It helps a lot! – hao Jul 19 '21 at 08:52
  • @hao This is the only answer on this post that correctly uses `array.map` to map the orders array to a new array, though I'd warn against using an array index as key or id property. It should be accepted answer. – Drew Reese Jul 19 '21 at 09:32
2

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)   
  }, []);
Dániel Boros
  • 381
  • 2
  • 14
  • 1
    It's another way for me!!! WOW~ It's all work for me! and I've seen `data.push()` before, but I didn't think it can be used in this way~ cool for me~ I'll write it down, and try this way in my other code!! Thanks a lot!!~ Means a lot~ – hao Jul 19 '21 at 08:56
  • Why are you using `array.map` to issue side-effect? If you are updating `data` then you should use `array.forEach`. If you want to use `array.map` then map to the new objects and update state with the returned array. See https://stackoverflow.com/a/68437412/8690857 – Drew Reese Jul 19 '21 at 09:30
  • @DrewReese What does it side-effect? I will pleasure to know my mistake. Could you please describe more about my? – Majid M. Jul 19 '21 at 09:36
  • 1
    `data.push` is the side-effect. https://stackoverflow.com/questions/34426458/javascript-difference-between-foreach-and-map – Drew Reese Jul 19 '21 at 09:36
1

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,
    },
  ])
squish
  • 846
  • 12
  • 24
1

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)
    },
 []);
Majid M.
  • 4,467
  • 1
  • 11
  • 29
  • 1
    Got it !! I'll write it down and keep it in mind, and I'll check my other code~Thanks for telling me this!! It helps a lot~ – hao Jul 19 '21 at 08:59
  • Why are you using `array.map` to issue side-effect? If you are updating `array` then you should use `array.forEach`. If you want to use `array.map` then map to the new objects and update state with the returned array. See https://stackoverflow.com/a/68437412/8690857 – Drew Reese Jul 19 '21 at 09:30
1

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);
  
     }, []);
  • Thank you for the answer and for helping me clarify my doubt, it means a lot to me!!! Now I know the way I used before will cause some problems, and I'll keep an eye on my code in future~ Thank you ~~ – hao Jul 19 '21 at 09:04
  • Why are you using `array.map` to issue side-effect? If you are updating `newStateArray` then you should use `array.forEach`. If you want to use `array.map` then map to the new objects and update state with the returned array. See https://stackoverflow.com/a/68437412/8690857 – Drew Reese Jul 19 '21 at 09:29