“this” in react higher order component












5















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.










share|improve this question

























  • 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 change deletedItem from the inside of WrappedComponent?

    – skyboyer
    Nov 25 '18 at 10:44


















5















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.










share|improve this question

























  • 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 change deletedItem from the inside of WrappedComponent?

    – skyboyer
    Nov 25 '18 at 10:44
















5












5








5


2






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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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





















  • 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 change deletedItem from the inside of WrappedComponent?

    – 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














2 Answers
2






active

oldest

votes


















2















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:




  1. 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.


  2. Props can change over time but this won't be reflected automatically in derived Instance properties/fields







share|improve this answer


























  • 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



















2














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);






share|improve this answer























    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%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









    2















    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:




    1. 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.


    2. Props can change over time but this won't be reflected automatically in derived Instance properties/fields







    share|improve this answer


























    • 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
















    2















    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:




    1. 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.


    2. Props can change over time but this won't be reflected automatically in derived Instance properties/fields







    share|improve this answer


























    • 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














    2












    2








    2








    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:




    1. 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.


    2. Props can change over time but this won't be reflected automatically in derived Instance properties/fields







    share|improve this answer
















    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:




    1. 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.


    2. Props can change over time but this won't be reflected automatically in derived Instance properties/fields








    share|improve this answer














    share|improve this answer



    share|improve this answer








    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



















    • 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













    2














    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);






    share|improve this answer




























      2














      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);






      share|improve this answer


























        2












        2








        2







        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);






        share|improve this answer













        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);







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 25 '18 at 11:05









        Karen GrigoryanKaren Grigoryan

        3,05011024




        3,05011024






























            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%2f53466519%2fthis-in-react-higher-order-component%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

            Ottavio Pratesi

            Tricia Helfer

            15 giugno