0

I'm fetching data from an API that gives me an array of objects. Each object contains some basic user info like first name, last name, email and so.

API response: [{first_name:"",...}, {first_name:"",...}, {first_name:"",...}]

After fetching the data from the API, I'm setting it to a state called 'data'

I'm rendering that array of objects through this code:

const renderData = () => {
    var rows = [];
    for (var i = 0; i < data.length; ++i) {
        rows.push(
            <tr key={i}>
                <td>{i+1}</td>
                <td>{data[i].first_name}</td>
                <td>{data[i].last_name}</td>
                <td>{data[i].email}</td>
                <td>{data[i].states}</td>
                <td>{data[i].city}</td>
                <td>{data[i].pincode}</td>
                <td className="action-btns">
                    <a className="edit-btn" href="/edit">EDIT</a>  // Notice this line
                    &nbsp;
                    <a className="delete-btn" href="/delete">DELETE</a>
                </td>
            </tr>
        );
    }
    return (
        <tbody>
            {rows}
        </tbody>  
    );
}

renderData gets called somewhere in the table:

export default MyComponent() {
    return() {
        <table>
            <thead>...</thead>
            {renderData()}  // notice this line
        </table>
    }
}

Now you might have notice that I have EDIT and DELETE button/link, Whenever user clicks on EDIT we go to /edit url then we render a component using react router. I want to pass data to another component that takes a single user prop object, the component is a form which will prefill the data with the props provided. But how do I know which object EDIT button has been clicked

I tried something naive like:

<a onClick={() => setNumber(i)} className="edit-btn" href="#">EDIT</a> // Notice the onClick event

I thought if i is the value in the for loop, only and if I get to know which element of array in the data is been clicked then maybe I can pass it as a prop. I'm not sure how to do this. But using this method only gives me 11 which is the length of the array 'data' retrived from the API.

<Router>
    <Switch>
        <Route exact path="/" component={App} />
        <Route path="/add" component={Add} />
        <Route path="/edit" component={Add(props)} /> // How do I pass props here from Add.js to Main.js
    </Switch>
</Router>
Emilia-tan
  • 35
  • 1
  • 9

1 Answers1

1

It gives you length of the array because there is a closure over i, use let i instead. More details here. But storing index might not be good idea, especially if you say remove element afterwards from array which may invalidate your stored index.

Instead of storing index, just store data[i] itself in state (e.g. the item which was clicked).

() => setClickedItem(data[i])

Also if you have hooks inside your renderData function, you might need to change your renderData to a component RenderData and use it as <RenderData/> instead of calling as function like you have now. Otherwise if you call it as function and have hooks inside, react will think those hooks belong to parent component, and unexpected things may happen.

Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
  • Thanks! using let does gives me the index I want in array, but how do I pass it as a prop to a another component that is using Routes. wait I'll update my post – Emilia-tan Sep 04 '21 at 17:54
  • I think I have an Idea I can use useHistory to push state to a another component. Thanks that was a huge help! – Emilia-tan Sep 04 '21 at 18:00
  • @Emilia-tan Yes but I told you also why using index isn't good idea. About Route, could you maybe embed ID of clicked item in URL and redirect to it? (like `"../edit/331"`) So then you can retrieve that ID from URL when matching Route is rendered. – Giorgi Moniava Sep 04 '21 at 18:01