When using map over onClick handler the inner function always gets the last element
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
|
show 2 more comments
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
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 casesteps.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
|
show 2 more comments
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
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
javascript reactjs jsx
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 casesteps.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
|
show 2 more comments
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 casesteps.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
|
show 2 more comments
1 Answer
1
active
oldest
votes
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>
);
}
}
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 theaddNeededStep
function,steps
and thestepId
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
|
show 1 more comment
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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>
);
}
}
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 theaddNeededStep
function,steps
and thestepId
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
|
show 1 more comment
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>
);
}
}
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 theaddNeededStep
function,steps
and thestepId
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
|
show 1 more comment
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>
);
}
}
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>
);
}
}
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 theaddNeededStep
function,steps
and thestepId
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
|
show 1 more comment
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 theaddNeededStep
function,steps
and thestepId
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
|
show 1 more comment
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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