Robert C
Robert C

Reputation: 806

How to increment state count in mapping function?

Goal is to increment the count in the mapping function while keeping track of the new value in state. "charlie" isn't updating, even on re-renders of the component, and subsequent runs of mapData. Meanwhile, every re-render/run of mapData continues to print the updated count outside "charlie". My code looks roughly like this:

const [data, setData] = useState([])
const [count, setCount] = useState(0)

const mapData = (apiData) => {
  const dataMapped = apiData.map((pic, index) => {
    return (
      setCount(prevState => (prevState+1))
      <div className="charlie">{count}</div> 
    )
  })
  setData(prevState => ([...prevState, ...dataMapped]))
}

return {
  <div>
    <div>{count}</div> {/* shows updated count every render */}
    <div>{data}</div>  {/* shows 0 every render*/}
  </div>
}

Upvotes: 0

Views: 6314

Answers (3)

Animus
Animus

Reputation: 853

If I got you right, this is what you are after, and it allows to avoid setState inside the loop:

const [data, setData] = useState([])
const [count, setCount] = useState(0)

const mapData = (apiData) => {
  const dataMapped = apiData.map((pic, index) => {
    return (
      <div className="charlie">{count + index}</div> 
    )
  })
  setCount(prevState => (prevState + apiData.length))
  setData(prevState => ([...prevState, ...dataMapped]))
}

return {
  <div>
    <div>{count}</div> {/* shows updated count every render */}
    <div>{data}</div>  {/* shows 0 every render*/}
  </div>
}

Upvotes: 0

Gasim
Gasim

Reputation: 7991

This is the second time in two days that I am seeing someone doing this. You need to separate your update logic from your render logic. I would strongly recommend storing JSX inside state unless it is some extremely rare scenario. I am going to comment on your code down below with all the mistakes:

const [data, setData] = useState([])
const [count, setCount] = useState(0)

const mapData = (apiData) => {
  const dataMapped = apiData.map((pic, index) => {
    return (
      // three things here:
      // 1. Never set state from inside a loop because it is going to break the order of hook calls
      // 2. Never try to update state during rendering (only do this if you are trying to replicate getDerivedStateFromProps in classes). Add it to useEffect.
      // 3. You do not need to calculate the count like this. You can just use index of the array to find the count.
      setCount(prevState => (prevState+1))
      <div className="charlie">{count}</div> 
    )
  })
  // Do not store React elements inside state
  setData(prevState => ([...prevState, ...dataMapped]))
}

// this where all your rendering should happen
return {
  <div>
    <div>{count}</div> {/* shows updated count every render */}
    <div>{data}</div>  {/* shows 0 every render*/}
  </div>
}

This would be a way I would go about doing what you are doing:

const [data, setData] = useState([])

const populateData = (apiData) => {
  setData(prevData => [...prevData, ...apiData]); // just in case I need the internals of the array. You can also map the array here to only store the counts
  // if you do not need api data, you can just retrieve the keys, which are the indices of the array
  // setData(prevData => [...prevData, ...apiData.keys()]);
}

return (
  <div>
    <div>{data.length}</div> {/* we already know count from array length */}
    <div>{data.map((item, idx) => (
      <div className="charlie">{idx + 1}</div> {/* render index to get count */}
    ))}</div> 
  </div>
);

Upvotes: 2

Dor Lugasi-Gal
Dor Lugasi-Gal

Reputation: 1572

first of all, your code doesn't compile

I am assuming that what you are trying to do is to keep track of the amount of data rendered

in that case, you can add the length of the API results to the count

const mapData = (apiData) => {
  const dataMapped = apiData.map((pic, index) => {
    return (
      <div className="charlie">{count}</div> 
    )
  })
  setCount(count + dataMapped.length);
  setData(prevState => ([...prevState, ...dataMapped]))
}

Upvotes: 1

Related Questions