“this” in react higher order component
I want to move shared functionality from my react components to a higher order component like this:
function withListFunctions(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
}
// my shared functionality
deleteItem() {
// Do something, then ...
this.setState({itemDeleted: true});
}
render() {
return (
<WrappedComponent
deleteItem={this.deleteItem}
/>
);
}
}
Using this kind of syntax requires to explicitely bind this in the constructor of the HOC:
this.deleteItem = this.deleteItem.bind(this);
.. but I wanted to bind the wrapped component instead. So what I tried in my wrapped component's constructor was
this.props.deleteItem = this.props.deleteItem.bind(this);
But this just resulted in a "Cannot assign to read only property" Error, as react props are meant to be read only.
I am aware that I could store the state item in the HOC and pass it down as a prop. But it would then be not accessible(writeable) anymore by other wrapped components functions, right? I wonder if there is a way to just share the unbound function and then bind it to the wrapped instance.
[Edit] I marked Abdul Rauf's answer as "accepted", nevertheless I want to state that Karen Grigoryan's answer is the solution I am actually using because it works and seems just appropiate for my app's complexity.
javascript reactjs
|
show 1 more comment
I want to move shared functionality from my react components to a higher order component like this:
function withListFunctions(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
}
// my shared functionality
deleteItem() {
// Do something, then ...
this.setState({itemDeleted: true});
}
render() {
return (
<WrappedComponent
deleteItem={this.deleteItem}
/>
);
}
}
Using this kind of syntax requires to explicitely bind this in the constructor of the HOC:
this.deleteItem = this.deleteItem.bind(this);
.. but I wanted to bind the wrapped component instead. So what I tried in my wrapped component's constructor was
this.props.deleteItem = this.props.deleteItem.bind(this);
But this just resulted in a "Cannot assign to read only property" Error, as react props are meant to be read only.
I am aware that I could store the state item in the HOC and pass it down as a prop. But it would then be not accessible(writeable) anymore by other wrapped components functions, right? I wonder if there is a way to just share the unbound function and then bind it to the wrapped instance.
[Edit] I marked Abdul Rauf's answer as "accepted", nevertheless I want to state that Karen Grigoryan's answer is the solution I am actually using because it works and seems just appropiate for my app's complexity.
javascript reactjs
Note sure if this will work, but have you tried this?this.deleteItem = this.deleteItem.bind(WrappedComponent)
– Patrick Hund
Nov 25 '18 at 10:25
@PatrickHund your solution binds to the class not to the instance
– Karen Grigoryan
Nov 25 '18 at 10:26
You're right, that doesn't work
– Patrick Hund
Nov 25 '18 at 10:38
Although React favours composition over inheritance, you can still use inheritance if it make sense. If you want to create a wrapped component without inheritance, I would pass the component to be wrapped as a prop.
– Keith
Nov 25 '18 at 10:42
"But it would then be not accessible(writeable) anymore by other wrapped components functions, right?" no, it will be writeable if you pass prop likesetDeletedItem={this.setDeletedItem}into<WrappedComponent .... But it looks like breaking encapsulation. do you really need to changedeletedItemfrom the inside ofWrappedComponent?
– skyboyer
Nov 25 '18 at 10:44
|
show 1 more comment
I want to move shared functionality from my react components to a higher order component like this:
function withListFunctions(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
}
// my shared functionality
deleteItem() {
// Do something, then ...
this.setState({itemDeleted: true});
}
render() {
return (
<WrappedComponent
deleteItem={this.deleteItem}
/>
);
}
}
Using this kind of syntax requires to explicitely bind this in the constructor of the HOC:
this.deleteItem = this.deleteItem.bind(this);
.. but I wanted to bind the wrapped component instead. So what I tried in my wrapped component's constructor was
this.props.deleteItem = this.props.deleteItem.bind(this);
But this just resulted in a "Cannot assign to read only property" Error, as react props are meant to be read only.
I am aware that I could store the state item in the HOC and pass it down as a prop. But it would then be not accessible(writeable) anymore by other wrapped components functions, right? I wonder if there is a way to just share the unbound function and then bind it to the wrapped instance.
[Edit] I marked Abdul Rauf's answer as "accepted", nevertheless I want to state that Karen Grigoryan's answer is the solution I am actually using because it works and seems just appropiate for my app's complexity.
javascript reactjs
I want to move shared functionality from my react components to a higher order component like this:
function withListFunctions(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
}
// my shared functionality
deleteItem() {
// Do something, then ...
this.setState({itemDeleted: true});
}
render() {
return (
<WrappedComponent
deleteItem={this.deleteItem}
/>
);
}
}
Using this kind of syntax requires to explicitely bind this in the constructor of the HOC:
this.deleteItem = this.deleteItem.bind(this);
.. but I wanted to bind the wrapped component instead. So what I tried in my wrapped component's constructor was
this.props.deleteItem = this.props.deleteItem.bind(this);
But this just resulted in a "Cannot assign to read only property" Error, as react props are meant to be read only.
I am aware that I could store the state item in the HOC and pass it down as a prop. But it would then be not accessible(writeable) anymore by other wrapped components functions, right? I wonder if there is a way to just share the unbound function and then bind it to the wrapped instance.
[Edit] I marked Abdul Rauf's answer as "accepted", nevertheless I want to state that Karen Grigoryan's answer is the solution I am actually using because it works and seems just appropiate for my app's complexity.
javascript reactjs
javascript reactjs
edited Dec 10 '18 at 22:41
Benni
asked Nov 25 '18 at 10:16
BenniBenni
35548
35548
Note sure if this will work, but have you tried this?this.deleteItem = this.deleteItem.bind(WrappedComponent)
– Patrick Hund
Nov 25 '18 at 10:25
@PatrickHund your solution binds to the class not to the instance
– Karen Grigoryan
Nov 25 '18 at 10:26
You're right, that doesn't work
– Patrick Hund
Nov 25 '18 at 10:38
Although React favours composition over inheritance, you can still use inheritance if it make sense. If you want to create a wrapped component without inheritance, I would pass the component to be wrapped as a prop.
– Keith
Nov 25 '18 at 10:42
"But it would then be not accessible(writeable) anymore by other wrapped components functions, right?" no, it will be writeable if you pass prop likesetDeletedItem={this.setDeletedItem}into<WrappedComponent .... But it looks like breaking encapsulation. do you really need to changedeletedItemfrom the inside ofWrappedComponent?
– skyboyer
Nov 25 '18 at 10:44
|
show 1 more comment
Note sure if this will work, but have you tried this?this.deleteItem = this.deleteItem.bind(WrappedComponent)
– Patrick Hund
Nov 25 '18 at 10:25
@PatrickHund your solution binds to the class not to the instance
– Karen Grigoryan
Nov 25 '18 at 10:26
You're right, that doesn't work
– Patrick Hund
Nov 25 '18 at 10:38
Although React favours composition over inheritance, you can still use inheritance if it make sense. If you want to create a wrapped component without inheritance, I would pass the component to be wrapped as a prop.
– Keith
Nov 25 '18 at 10:42
"But it would then be not accessible(writeable) anymore by other wrapped components functions, right?" no, it will be writeable if you pass prop likesetDeletedItem={this.setDeletedItem}into<WrappedComponent .... But it looks like breaking encapsulation. do you really need to changedeletedItemfrom the inside ofWrappedComponent?
– skyboyer
Nov 25 '18 at 10:44
Note sure if this will work, but have you tried this?
this.deleteItem = this.deleteItem.bind(WrappedComponent)– Patrick Hund
Nov 25 '18 at 10:25
Note sure if this will work, but have you tried this?
this.deleteItem = this.deleteItem.bind(WrappedComponent)– Patrick Hund
Nov 25 '18 at 10:25
@PatrickHund your solution binds to the class not to the instance
– Karen Grigoryan
Nov 25 '18 at 10:26
@PatrickHund your solution binds to the class not to the instance
– Karen Grigoryan
Nov 25 '18 at 10:26
You're right, that doesn't work
– Patrick Hund
Nov 25 '18 at 10:38
You're right, that doesn't work
– Patrick Hund
Nov 25 '18 at 10:38
Although React favours composition over inheritance, you can still use inheritance if it make sense. If you want to create a wrapped component without inheritance, I would pass the component to be wrapped as a prop.
– Keith
Nov 25 '18 at 10:42
Although React favours composition over inheritance, you can still use inheritance if it make sense. If you want to create a wrapped component without inheritance, I would pass the component to be wrapped as a prop.
– Keith
Nov 25 '18 at 10:42
"But it would then be not accessible(writeable) anymore by other wrapped components functions, right?" no, it will be writeable if you pass prop like
setDeletedItem={this.setDeletedItem} into <WrappedComponent .... But it looks like breaking encapsulation. do you really need to change deletedItem from the inside of WrappedComponent?– skyboyer
Nov 25 '18 at 10:44
"But it would then be not accessible(writeable) anymore by other wrapped components functions, right?" no, it will be writeable if you pass prop like
setDeletedItem={this.setDeletedItem} into <WrappedComponent .... But it looks like breaking encapsulation. do you really need to change deletedItem from the inside of WrappedComponent?– skyboyer
Nov 25 '18 at 10:44
|
show 1 more comment
2 Answers
2
active
oldest
votes
I am aware that I could store the state item in the HOC and pass it
down as a prop. But it would then be not accessible(writeable) anymore
by other wrapped components functions, right?
You should store shared state in HOC. You can pass multiple state update methods to Wrapped components that they can call internally to update state indirectly.
If you don't want to pass multiple state update methods then we have 2 options:
Option 1: Create a single dispatch method in HOC that takes action and optional payload and pass it to Wrapped components.
// Do not mutate state in reducer. always return a new state
reducer(state, action) {
switch (action.type) {
case 'delete':
// return final state after delete
case 'add':
// return final state after add using action.payload
case 'update':
// return final state after update using action.payload
default:
// A reducer must always return a valid state.
// Alternatively you can throw an error if an invalid action is dispatched.
return state;
}
}
dispatch(action) {
const updatedState = this.reducer(this.state, action)
this.setState(updatedState);
}
Option 2: Use useReducer hook if you can use latest react with hooks support.
I wonder if there is a way to just share the unbound function and then
bind it to the wrapped instance.
Technically you can do that (Check Karen Grigoryan's answer). But it is considered a bad practice because of many reasons. Few of those are:
Its against encapsulation principles. (State is in Child component and state update logic is in parent component). Parent component shouldn't know anything about state of child components.
Props can change over time but this won't be reflected automatically in derived
Instance properties/fields
Could you concretize in a few words why Karen Grigoryans answer is considered a bad practice? Does it have concrete drawbacks, or does it just not follow the framework's opinion how things should be structured?
– Benni
Nov 25 '18 at 19:50
add a comment |
props are read only by design.
React elements are immutable. Once you create an element, you can’t change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
So technically one of the ways to bind deleteItem to WrappedComponent context, is to just bind it in WrappedComponent constructor:
codesandbox example
this.deleteItem = this.props.deleteItem.bind(this);
add a 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%2f53466519%2fthis-in-react-higher-order-component%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
I am aware that I could store the state item in the HOC and pass it
down as a prop. But it would then be not accessible(writeable) anymore
by other wrapped components functions, right?
You should store shared state in HOC. You can pass multiple state update methods to Wrapped components that they can call internally to update state indirectly.
If you don't want to pass multiple state update methods then we have 2 options:
Option 1: Create a single dispatch method in HOC that takes action and optional payload and pass it to Wrapped components.
// Do not mutate state in reducer. always return a new state
reducer(state, action) {
switch (action.type) {
case 'delete':
// return final state after delete
case 'add':
// return final state after add using action.payload
case 'update':
// return final state after update using action.payload
default:
// A reducer must always return a valid state.
// Alternatively you can throw an error if an invalid action is dispatched.
return state;
}
}
dispatch(action) {
const updatedState = this.reducer(this.state, action)
this.setState(updatedState);
}
Option 2: Use useReducer hook if you can use latest react with hooks support.
I wonder if there is a way to just share the unbound function and then
bind it to the wrapped instance.
Technically you can do that (Check Karen Grigoryan's answer). But it is considered a bad practice because of many reasons. Few of those are:
Its against encapsulation principles. (State is in Child component and state update logic is in parent component). Parent component shouldn't know anything about state of child components.
Props can change over time but this won't be reflected automatically in derived
Instance properties/fields
Could you concretize in a few words why Karen Grigoryans answer is considered a bad practice? Does it have concrete drawbacks, or does it just not follow the framework's opinion how things should be structured?
– Benni
Nov 25 '18 at 19:50
add a comment |
I am aware that I could store the state item in the HOC and pass it
down as a prop. But it would then be not accessible(writeable) anymore
by other wrapped components functions, right?
You should store shared state in HOC. You can pass multiple state update methods to Wrapped components that they can call internally to update state indirectly.
If you don't want to pass multiple state update methods then we have 2 options:
Option 1: Create a single dispatch method in HOC that takes action and optional payload and pass it to Wrapped components.
// Do not mutate state in reducer. always return a new state
reducer(state, action) {
switch (action.type) {
case 'delete':
// return final state after delete
case 'add':
// return final state after add using action.payload
case 'update':
// return final state after update using action.payload
default:
// A reducer must always return a valid state.
// Alternatively you can throw an error if an invalid action is dispatched.
return state;
}
}
dispatch(action) {
const updatedState = this.reducer(this.state, action)
this.setState(updatedState);
}
Option 2: Use useReducer hook if you can use latest react with hooks support.
I wonder if there is a way to just share the unbound function and then
bind it to the wrapped instance.
Technically you can do that (Check Karen Grigoryan's answer). But it is considered a bad practice because of many reasons. Few of those are:
Its against encapsulation principles. (State is in Child component and state update logic is in parent component). Parent component shouldn't know anything about state of child components.
Props can change over time but this won't be reflected automatically in derived
Instance properties/fields
Could you concretize in a few words why Karen Grigoryans answer is considered a bad practice? Does it have concrete drawbacks, or does it just not follow the framework's opinion how things should be structured?
– Benni
Nov 25 '18 at 19:50
add a comment |
I am aware that I could store the state item in the HOC and pass it
down as a prop. But it would then be not accessible(writeable) anymore
by other wrapped components functions, right?
You should store shared state in HOC. You can pass multiple state update methods to Wrapped components that they can call internally to update state indirectly.
If you don't want to pass multiple state update methods then we have 2 options:
Option 1: Create a single dispatch method in HOC that takes action and optional payload and pass it to Wrapped components.
// Do not mutate state in reducer. always return a new state
reducer(state, action) {
switch (action.type) {
case 'delete':
// return final state after delete
case 'add':
// return final state after add using action.payload
case 'update':
// return final state after update using action.payload
default:
// A reducer must always return a valid state.
// Alternatively you can throw an error if an invalid action is dispatched.
return state;
}
}
dispatch(action) {
const updatedState = this.reducer(this.state, action)
this.setState(updatedState);
}
Option 2: Use useReducer hook if you can use latest react with hooks support.
I wonder if there is a way to just share the unbound function and then
bind it to the wrapped instance.
Technically you can do that (Check Karen Grigoryan's answer). But it is considered a bad practice because of many reasons. Few of those are:
Its against encapsulation principles. (State is in Child component and state update logic is in parent component). Parent component shouldn't know anything about state of child components.
Props can change over time but this won't be reflected automatically in derived
Instance properties/fields
I am aware that I could store the state item in the HOC and pass it
down as a prop. But it would then be not accessible(writeable) anymore
by other wrapped components functions, right?
You should store shared state in HOC. You can pass multiple state update methods to Wrapped components that they can call internally to update state indirectly.
If you don't want to pass multiple state update methods then we have 2 options:
Option 1: Create a single dispatch method in HOC that takes action and optional payload and pass it to Wrapped components.
// Do not mutate state in reducer. always return a new state
reducer(state, action) {
switch (action.type) {
case 'delete':
// return final state after delete
case 'add':
// return final state after add using action.payload
case 'update':
// return final state after update using action.payload
default:
// A reducer must always return a valid state.
// Alternatively you can throw an error if an invalid action is dispatched.
return state;
}
}
dispatch(action) {
const updatedState = this.reducer(this.state, action)
this.setState(updatedState);
}
Option 2: Use useReducer hook if you can use latest react with hooks support.
I wonder if there is a way to just share the unbound function and then
bind it to the wrapped instance.
Technically you can do that (Check Karen Grigoryan's answer). But it is considered a bad practice because of many reasons. Few of those are:
Its against encapsulation principles. (State is in Child component and state update logic is in parent component). Parent component shouldn't know anything about state of child components.
Props can change over time but this won't be reflected automatically in derived
Instance properties/fields
edited Nov 26 '18 at 10:20
answered Nov 25 '18 at 10:42
Abdul RaufAbdul Rauf
2,55332450
2,55332450
Could you concretize in a few words why Karen Grigoryans answer is considered a bad practice? Does it have concrete drawbacks, or does it just not follow the framework's opinion how things should be structured?
– Benni
Nov 25 '18 at 19:50
add a comment |
Could you concretize in a few words why Karen Grigoryans answer is considered a bad practice? Does it have concrete drawbacks, or does it just not follow the framework's opinion how things should be structured?
– Benni
Nov 25 '18 at 19:50
Could you concretize in a few words why Karen Grigoryans answer is considered a bad practice? Does it have concrete drawbacks, or does it just not follow the framework's opinion how things should be structured?
– Benni
Nov 25 '18 at 19:50
Could you concretize in a few words why Karen Grigoryans answer is considered a bad practice? Does it have concrete drawbacks, or does it just not follow the framework's opinion how things should be structured?
– Benni
Nov 25 '18 at 19:50
add a comment |
props are read only by design.
React elements are immutable. Once you create an element, you can’t change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
So technically one of the ways to bind deleteItem to WrappedComponent context, is to just bind it in WrappedComponent constructor:
codesandbox example
this.deleteItem = this.props.deleteItem.bind(this);
add a comment |
props are read only by design.
React elements are immutable. Once you create an element, you can’t change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
So technically one of the ways to bind deleteItem to WrappedComponent context, is to just bind it in WrappedComponent constructor:
codesandbox example
this.deleteItem = this.props.deleteItem.bind(this);
add a comment |
props are read only by design.
React elements are immutable. Once you create an element, you can’t change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
So technically one of the ways to bind deleteItem to WrappedComponent context, is to just bind it in WrappedComponent constructor:
codesandbox example
this.deleteItem = this.props.deleteItem.bind(this);
props are read only by design.
React elements are immutable. Once you create an element, you can’t change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
So technically one of the ways to bind deleteItem to WrappedComponent context, is to just bind it in WrappedComponent constructor:
codesandbox example
this.deleteItem = this.props.deleteItem.bind(this);
answered Nov 25 '18 at 11:05
Karen GrigoryanKaren Grigoryan
3,05011024
3,05011024
add a comment |
add a 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%2f53466519%2fthis-in-react-higher-order-component%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
Note sure if this will work, but have you tried this?
this.deleteItem = this.deleteItem.bind(WrappedComponent)– Patrick Hund
Nov 25 '18 at 10:25
@PatrickHund your solution binds to the class not to the instance
– Karen Grigoryan
Nov 25 '18 at 10:26
You're right, that doesn't work
– Patrick Hund
Nov 25 '18 at 10:38
Although React favours composition over inheritance, you can still use inheritance if it make sense. If you want to create a wrapped component without inheritance, I would pass the component to be wrapped as a prop.
– Keith
Nov 25 '18 at 10:42
"But it would then be not accessible(writeable) anymore by other wrapped components functions, right?" no, it will be writeable if you pass prop like
setDeletedItem={this.setDeletedItem}into<WrappedComponent .... But it looks like breaking encapsulation. do you really need to changedeletedItemfrom the inside ofWrappedComponent?– skyboyer
Nov 25 '18 at 10:44