When using map over onClick handler the inner function always gets the last element












1















I have a nested JSX component with a mapping function with an inner mapping function:



{steps.map(({
step_id: stepId,
step_name: stepName
}) => (
<TableRow key={stepId}>
(...)
{steps.map(
({ step_id: id, name }) => (
{stepId} // <- rendering the stepId leads to list of different numbers
<MenuItem
key={id}
onClick={() => {
this.addNeededStep(stepId, id); // <- stepId is ALWAYS the last in the list
this.closeNeededStepSelector();
}}
>
{name}
</MenuItem>)
)}
</TableRow>
))}


Now, when the onClick handler is clicked the addNeededStep function always receive the last stepId of the steps.



I expect it to be the stepId as specified on line 2 (step_id: stepId). Why does this happen? And how can I fix it?



What I tried is using bind to bind the stepId because I thought it was a JavaScript issue with enclosed functions losing their outer scope, but that did not help.










share|improve this question


















  • 2





    Isn't it weird that your map callback is also performing a map on the same steps array ?

    – nubinub
    Jan 2 at 17:03








  • 2





    You are calling the function after all the mapping has ended leaving just the last value. If you want to use it you need to pass is as a prop to each map instance. Also, we can't see your source over which you map, but it seems odd that you are mapping over same thing in a nested case steps.map.

    – Vrle
    Jan 2 at 17:05











  • @nubinub why is that weird?

    – Erwin Rooijakkers
    Jan 3 at 8:43











  • @Vrle It creates 20 rows or so for every step id... So if you print the row I see stepId 1 till 20, but if I call the onClick handler it always has the last value (even if another stepId is displayed). Do I understand correctly that JavaScript is not creating a proper closure in the onClick handler where the environment is captured?

    – Erwin Rooijakkers
    Jan 3 at 8:44













  • @nubinub. If stepId is 1 till 5 it creates a list like: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]].

    – Erwin Rooijakkers
    Jan 3 at 8:48


















1















I have a nested JSX component with a mapping function with an inner mapping function:



{steps.map(({
step_id: stepId,
step_name: stepName
}) => (
<TableRow key={stepId}>
(...)
{steps.map(
({ step_id: id, name }) => (
{stepId} // <- rendering the stepId leads to list of different numbers
<MenuItem
key={id}
onClick={() => {
this.addNeededStep(stepId, id); // <- stepId is ALWAYS the last in the list
this.closeNeededStepSelector();
}}
>
{name}
</MenuItem>)
)}
</TableRow>
))}


Now, when the onClick handler is clicked the addNeededStep function always receive the last stepId of the steps.



I expect it to be the stepId as specified on line 2 (step_id: stepId). Why does this happen? And how can I fix it?



What I tried is using bind to bind the stepId because I thought it was a JavaScript issue with enclosed functions losing their outer scope, but that did not help.










share|improve this question


















  • 2





    Isn't it weird that your map callback is also performing a map on the same steps array ?

    – nubinub
    Jan 2 at 17:03








  • 2





    You are calling the function after all the mapping has ended leaving just the last value. If you want to use it you need to pass is as a prop to each map instance. Also, we can't see your source over which you map, but it seems odd that you are mapping over same thing in a nested case steps.map.

    – Vrle
    Jan 2 at 17:05











  • @nubinub why is that weird?

    – Erwin Rooijakkers
    Jan 3 at 8:43











  • @Vrle It creates 20 rows or so for every step id... So if you print the row I see stepId 1 till 20, but if I call the onClick handler it always has the last value (even if another stepId is displayed). Do I understand correctly that JavaScript is not creating a proper closure in the onClick handler where the environment is captured?

    – Erwin Rooijakkers
    Jan 3 at 8:44













  • @nubinub. If stepId is 1 till 5 it creates a list like: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]].

    – Erwin Rooijakkers
    Jan 3 at 8:48
















1












1








1








I have a nested JSX component with a mapping function with an inner mapping function:



{steps.map(({
step_id: stepId,
step_name: stepName
}) => (
<TableRow key={stepId}>
(...)
{steps.map(
({ step_id: id, name }) => (
{stepId} // <- rendering the stepId leads to list of different numbers
<MenuItem
key={id}
onClick={() => {
this.addNeededStep(stepId, id); // <- stepId is ALWAYS the last in the list
this.closeNeededStepSelector();
}}
>
{name}
</MenuItem>)
)}
</TableRow>
))}


Now, when the onClick handler is clicked the addNeededStep function always receive the last stepId of the steps.



I expect it to be the stepId as specified on line 2 (step_id: stepId). Why does this happen? And how can I fix it?



What I tried is using bind to bind the stepId because I thought it was a JavaScript issue with enclosed functions losing their outer scope, but that did not help.










share|improve this question














I have a nested JSX component with a mapping function with an inner mapping function:



{steps.map(({
step_id: stepId,
step_name: stepName
}) => (
<TableRow key={stepId}>
(...)
{steps.map(
({ step_id: id, name }) => (
{stepId} // <- rendering the stepId leads to list of different numbers
<MenuItem
key={id}
onClick={() => {
this.addNeededStep(stepId, id); // <- stepId is ALWAYS the last in the list
this.closeNeededStepSelector();
}}
>
{name}
</MenuItem>)
)}
</TableRow>
))}


Now, when the onClick handler is clicked the addNeededStep function always receive the last stepId of the steps.



I expect it to be the stepId as specified on line 2 (step_id: stepId). Why does this happen? And how can I fix it?



What I tried is using bind to bind the stepId because I thought it was a JavaScript issue with enclosed functions losing their outer scope, but that did not help.







javascript reactjs jsx






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 2 at 16:55









Erwin RooijakkersErwin Rooijakkers

4,98284497




4,98284497








  • 2





    Isn't it weird that your map callback is also performing a map on the same steps array ?

    – nubinub
    Jan 2 at 17:03








  • 2





    You are calling the function after all the mapping has ended leaving just the last value. If you want to use it you need to pass is as a prop to each map instance. Also, we can't see your source over which you map, but it seems odd that you are mapping over same thing in a nested case steps.map.

    – Vrle
    Jan 2 at 17:05











  • @nubinub why is that weird?

    – Erwin Rooijakkers
    Jan 3 at 8:43











  • @Vrle It creates 20 rows or so for every step id... So if you print the row I see stepId 1 till 20, but if I call the onClick handler it always has the last value (even if another stepId is displayed). Do I understand correctly that JavaScript is not creating a proper closure in the onClick handler where the environment is captured?

    – Erwin Rooijakkers
    Jan 3 at 8:44













  • @nubinub. If stepId is 1 till 5 it creates a list like: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]].

    – Erwin Rooijakkers
    Jan 3 at 8:48
















  • 2





    Isn't it weird that your map callback is also performing a map on the same steps array ?

    – nubinub
    Jan 2 at 17:03








  • 2





    You are calling the function after all the mapping has ended leaving just the last value. If you want to use it you need to pass is as a prop to each map instance. Also, we can't see your source over which you map, but it seems odd that you are mapping over same thing in a nested case steps.map.

    – Vrle
    Jan 2 at 17:05











  • @nubinub why is that weird?

    – Erwin Rooijakkers
    Jan 3 at 8:43











  • @Vrle It creates 20 rows or so for every step id... So if you print the row I see stepId 1 till 20, but if I call the onClick handler it always has the last value (even if another stepId is displayed). Do I understand correctly that JavaScript is not creating a proper closure in the onClick handler where the environment is captured?

    – Erwin Rooijakkers
    Jan 3 at 8:44













  • @nubinub. If stepId is 1 till 5 it creates a list like: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]].

    – Erwin Rooijakkers
    Jan 3 at 8:48










2




2





Isn't it weird that your map callback is also performing a map on the same steps array ?

– nubinub
Jan 2 at 17:03







Isn't it weird that your map callback is also performing a map on the same steps array ?

– nubinub
Jan 2 at 17:03






2




2





You are calling the function after all the mapping has ended leaving just the last value. If you want to use it you need to pass is as a prop to each map instance. Also, we can't see your source over which you map, but it seems odd that you are mapping over same thing in a nested case steps.map.

– Vrle
Jan 2 at 17:05





You are calling the function after all the mapping has ended leaving just the last value. If you want to use it you need to pass is as a prop to each map instance. Also, we can't see your source over which you map, but it seems odd that you are mapping over same thing in a nested case steps.map.

– Vrle
Jan 2 at 17:05













@nubinub why is that weird?

– Erwin Rooijakkers
Jan 3 at 8:43





@nubinub why is that weird?

– Erwin Rooijakkers
Jan 3 at 8:43













@Vrle It creates 20 rows or so for every step id... So if you print the row I see stepId 1 till 20, but if I call the onClick handler it always has the last value (even if another stepId is displayed). Do I understand correctly that JavaScript is not creating a proper closure in the onClick handler where the environment is captured?

– Erwin Rooijakkers
Jan 3 at 8:44







@Vrle It creates 20 rows or so for every step id... So if you print the row I see stepId 1 till 20, but if I call the onClick handler it always has the last value (even if another stepId is displayed). Do I understand correctly that JavaScript is not creating a proper closure in the onClick handler where the environment is captured?

– Erwin Rooijakkers
Jan 3 at 8:44















@nubinub. If stepId is 1 till 5 it creates a list like: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]].

– Erwin Rooijakkers
Jan 3 at 8:48







@nubinub. If stepId is 1 till 5 it creates a list like: [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]].

– Erwin Rooijakkers
Jan 3 at 8:48














1 Answer
1






active

oldest

votes


















1














This seems to work perfectly fine the way you wrote it, at least with this simple example on codepen. Can you provide more of your source code, maybe something interferring with the steps values ?



class Clock extends React.Component {
render() {
const test = [{elem:1},{elem:2},{elem:3},{elem:4},{elem:5}]
return (
<div>
{
test.map(({elem: initElem}) =>
test.map(elem => {
return (
<div onClick={() => { alert(initElem);} }>
{initElem}
</div>
);
})
)

}
</div>
);
}
}





share|improve this answer


























  • Thanks. Unfortunately assigning stepId to a new variable named currentStepId and then returning the JSX does does not solve the problem. The onClick handler keeps referring to the last id.

    – Erwin Rooijakkers
    Jan 3 at 9:31













  • I try to put it in a prop

    – Erwin Rooijakkers
    Jan 3 at 9:32











  • This is the last project I will use plain React for. Reagent + ClojureScript is so much nicer. reagent-project.github.io. All these problems are non-existent.

    – Erwin Rooijakkers
    Jan 3 at 9:32













  • It seems to works pretty fine even without the scoped const. codepen.io/anon/pen/EGQadd

    – nubinub
    Jan 3 at 9:46











  • Thanks @nubinub for the effort. Strange, maybe in my specific code it was different. What did work was extracting the NeededStepSelector in a separate component. I passed the addNeededStep function, steps and the stepId as props. I.e. <NeededStepSelector stepId={stepId} steps={steps} addNeededStep={(id, neededId) => this.addNeededStep(id, neededId)} />. That was the only thing that did work in my case. Creating a separate prop also increased performance.

    – Erwin Rooijakkers
    Jan 3 at 9:53














Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54010228%2fwhen-using-map-over-onclick-handler-the-inner-function-always-gets-the-last-elem%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














This seems to work perfectly fine the way you wrote it, at least with this simple example on codepen. Can you provide more of your source code, maybe something interferring with the steps values ?



class Clock extends React.Component {
render() {
const test = [{elem:1},{elem:2},{elem:3},{elem:4},{elem:5}]
return (
<div>
{
test.map(({elem: initElem}) =>
test.map(elem => {
return (
<div onClick={() => { alert(initElem);} }>
{initElem}
</div>
);
})
)

}
</div>
);
}
}





share|improve this answer


























  • Thanks. Unfortunately assigning stepId to a new variable named currentStepId and then returning the JSX does does not solve the problem. The onClick handler keeps referring to the last id.

    – Erwin Rooijakkers
    Jan 3 at 9:31













  • I try to put it in a prop

    – Erwin Rooijakkers
    Jan 3 at 9:32











  • This is the last project I will use plain React for. Reagent + ClojureScript is so much nicer. reagent-project.github.io. All these problems are non-existent.

    – Erwin Rooijakkers
    Jan 3 at 9:32













  • It seems to works pretty fine even without the scoped const. codepen.io/anon/pen/EGQadd

    – nubinub
    Jan 3 at 9:46











  • Thanks @nubinub for the effort. Strange, maybe in my specific code it was different. What did work was extracting the NeededStepSelector in a separate component. I passed the addNeededStep function, steps and the stepId as props. I.e. <NeededStepSelector stepId={stepId} steps={steps} addNeededStep={(id, neededId) => this.addNeededStep(id, neededId)} />. That was the only thing that did work in my case. Creating a separate prop also increased performance.

    – Erwin Rooijakkers
    Jan 3 at 9:53


















1














This seems to work perfectly fine the way you wrote it, at least with this simple example on codepen. Can you provide more of your source code, maybe something interferring with the steps values ?



class Clock extends React.Component {
render() {
const test = [{elem:1},{elem:2},{elem:3},{elem:4},{elem:5}]
return (
<div>
{
test.map(({elem: initElem}) =>
test.map(elem => {
return (
<div onClick={() => { alert(initElem);} }>
{initElem}
</div>
);
})
)

}
</div>
);
}
}





share|improve this answer


























  • Thanks. Unfortunately assigning stepId to a new variable named currentStepId and then returning the JSX does does not solve the problem. The onClick handler keeps referring to the last id.

    – Erwin Rooijakkers
    Jan 3 at 9:31













  • I try to put it in a prop

    – Erwin Rooijakkers
    Jan 3 at 9:32











  • This is the last project I will use plain React for. Reagent + ClojureScript is so much nicer. reagent-project.github.io. All these problems are non-existent.

    – Erwin Rooijakkers
    Jan 3 at 9:32













  • It seems to works pretty fine even without the scoped const. codepen.io/anon/pen/EGQadd

    – nubinub
    Jan 3 at 9:46











  • Thanks @nubinub for the effort. Strange, maybe in my specific code it was different. What did work was extracting the NeededStepSelector in a separate component. I passed the addNeededStep function, steps and the stepId as props. I.e. <NeededStepSelector stepId={stepId} steps={steps} addNeededStep={(id, neededId) => this.addNeededStep(id, neededId)} />. That was the only thing that did work in my case. Creating a separate prop also increased performance.

    – Erwin Rooijakkers
    Jan 3 at 9:53
















1












1








1







This seems to work perfectly fine the way you wrote it, at least with this simple example on codepen. Can you provide more of your source code, maybe something interferring with the steps values ?



class Clock extends React.Component {
render() {
const test = [{elem:1},{elem:2},{elem:3},{elem:4},{elem:5}]
return (
<div>
{
test.map(({elem: initElem}) =>
test.map(elem => {
return (
<div onClick={() => { alert(initElem);} }>
{initElem}
</div>
);
})
)

}
</div>
);
}
}





share|improve this answer















This seems to work perfectly fine the way you wrote it, at least with this simple example on codepen. Can you provide more of your source code, maybe something interferring with the steps values ?



class Clock extends React.Component {
render() {
const test = [{elem:1},{elem:2},{elem:3},{elem:4},{elem:5}]
return (
<div>
{
test.map(({elem: initElem}) =>
test.map(elem => {
return (
<div onClick={() => { alert(initElem);} }>
{initElem}
</div>
);
})
)

}
</div>
);
}
}






share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 3 at 9:54

























answered Jan 3 at 9:18









nubinubnubinub

9712619




9712619













  • Thanks. Unfortunately assigning stepId to a new variable named currentStepId and then returning the JSX does does not solve the problem. The onClick handler keeps referring to the last id.

    – Erwin Rooijakkers
    Jan 3 at 9:31













  • I try to put it in a prop

    – Erwin Rooijakkers
    Jan 3 at 9:32











  • This is the last project I will use plain React for. Reagent + ClojureScript is so much nicer. reagent-project.github.io. All these problems are non-existent.

    – Erwin Rooijakkers
    Jan 3 at 9:32













  • It seems to works pretty fine even without the scoped const. codepen.io/anon/pen/EGQadd

    – nubinub
    Jan 3 at 9:46











  • Thanks @nubinub for the effort. Strange, maybe in my specific code it was different. What did work was extracting the NeededStepSelector in a separate component. I passed the addNeededStep function, steps and the stepId as props. I.e. <NeededStepSelector stepId={stepId} steps={steps} addNeededStep={(id, neededId) => this.addNeededStep(id, neededId)} />. That was the only thing that did work in my case. Creating a separate prop also increased performance.

    – Erwin Rooijakkers
    Jan 3 at 9:53





















  • Thanks. Unfortunately assigning stepId to a new variable named currentStepId and then returning the JSX does does not solve the problem. The onClick handler keeps referring to the last id.

    – Erwin Rooijakkers
    Jan 3 at 9:31













  • I try to put it in a prop

    – Erwin Rooijakkers
    Jan 3 at 9:32











  • This is the last project I will use plain React for. Reagent + ClojureScript is so much nicer. reagent-project.github.io. All these problems are non-existent.

    – Erwin Rooijakkers
    Jan 3 at 9:32













  • It seems to works pretty fine even without the scoped const. codepen.io/anon/pen/EGQadd

    – nubinub
    Jan 3 at 9:46











  • Thanks @nubinub for the effort. Strange, maybe in my specific code it was different. What did work was extracting the NeededStepSelector in a separate component. I passed the addNeededStep function, steps and the stepId as props. I.e. <NeededStepSelector stepId={stepId} steps={steps} addNeededStep={(id, neededId) => this.addNeededStep(id, neededId)} />. That was the only thing that did work in my case. Creating a separate prop also increased performance.

    – Erwin Rooijakkers
    Jan 3 at 9:53



















Thanks. Unfortunately assigning stepId to a new variable named currentStepId and then returning the JSX does does not solve the problem. The onClick handler keeps referring to the last id.

– Erwin Rooijakkers
Jan 3 at 9:31







Thanks. Unfortunately assigning stepId to a new variable named currentStepId and then returning the JSX does does not solve the problem. The onClick handler keeps referring to the last id.

– Erwin Rooijakkers
Jan 3 at 9:31















I try to put it in a prop

– Erwin Rooijakkers
Jan 3 at 9:32





I try to put it in a prop

– Erwin Rooijakkers
Jan 3 at 9:32













This is the last project I will use plain React for. Reagent + ClojureScript is so much nicer. reagent-project.github.io. All these problems are non-existent.

– Erwin Rooijakkers
Jan 3 at 9:32







This is the last project I will use plain React for. Reagent + ClojureScript is so much nicer. reagent-project.github.io. All these problems are non-existent.

– Erwin Rooijakkers
Jan 3 at 9:32















It seems to works pretty fine even without the scoped const. codepen.io/anon/pen/EGQadd

– nubinub
Jan 3 at 9:46





It seems to works pretty fine even without the scoped const. codepen.io/anon/pen/EGQadd

– nubinub
Jan 3 at 9:46













Thanks @nubinub for the effort. Strange, maybe in my specific code it was different. What did work was extracting the NeededStepSelector in a separate component. I passed the addNeededStep function, steps and the stepId as props. I.e. <NeededStepSelector stepId={stepId} steps={steps} addNeededStep={(id, neededId) => this.addNeededStep(id, neededId)} />. That was the only thing that did work in my case. Creating a separate prop also increased performance.

– Erwin Rooijakkers
Jan 3 at 9:53







Thanks @nubinub for the effort. Strange, maybe in my specific code it was different. What did work was extracting the NeededStepSelector in a separate component. I passed the addNeededStep function, steps and the stepId as props. I.e. <NeededStepSelector stepId={stepId} steps={steps} addNeededStep={(id, neededId) => this.addNeededStep(id, neededId)} />. That was the only thing that did work in my case. Creating a separate prop also increased performance.

– Erwin Rooijakkers
Jan 3 at 9:53






















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54010228%2fwhen-using-map-over-onclick-handler-the-inner-function-always-gets-the-last-elem%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

A Topological Invariant for $pi_3(U(n))$