Reputation: 5
i am learning React and I have this code snippet that builds a html table (data has 100+ object entries) by returning the necessary JSX.
For context, data is also an array of objects:
[{},{},{}]
const [trafficData, setTrafficData] = useState();
getTrafficDetails().then(r => {
setTrafficData(r);
})
<TrafficWidget data={trafficData} />
consumed in:
const TrafficWidget = ({ data }) => {
let [trafficStatus, setTrafficStatus] = useState([]);
if (data && data.length > 0) {
const mapData = data.map((item) => {
return (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.totalEmission}</td>
</tr>
);
});
setTrafficStatus(mapData);
}
return(<tbody>{trafficStatus}</tbody>)
}
The problem that I have is that when i interrogate mapData
array, it shows as {$$typeof: Symbol(react.element), type: "tr", key: "082", ref: null, props: {…}, …}
and then causes a Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
Why does it come up as an object when i'm returning jsx and why would this cause an infinite loop?
Upvotes: 0
Views: 570
Reputation: 1018
const { Fragment } = React
const TrafficWidget = ({
data
}) => (
<tbody>
{data.map((item) => (
<Fragment key={item.id}>
<tr>
<td>{item.name}</td>
<td>{item.totalEmission}</td>
</tr>
</Fragment>
))}
</tbody>
)
let data = [
{
name: "Henry",
totalEmission: 500,
id: "936-DEF12"
},
{
name: "Nick",
totalEmission: 200,
id: "843-7266B"
},
]
ReactDOM.render(<TrafficWidget data={data} />, document.getElementById('main'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<main id="main">loading or error...</main>
Upvotes: 1
Reputation: 15268
You are creating a new array object with .map
each time, causing the state to change at every render call, forcing it to re-render in a loop. Re-render triggered by data
changing should be enough to signal a need for re-render.
State should be used to store and mutate the state of data
or something else being given to your components as props. Not for storing your component.
You want to let React do the work of reconciling changes in your components, which is what it does well.
You can just feed your mapped components directly in your render loop.
const TrafficWidget = ({ data }) => {
// NOTE: You actually don't need to check the length here. Empty arrays are handled like no-op.
const trafficStatus =
data && data.length > 0 && data.map((item) => {
return (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.totalEmission}</td>
</tr>
);
});
return(<tbody>{trafficStatus}</tbody>);
}
Upvotes: 1