Search code examples
javascriptvue.jsvuejs2observable

Vue data binding doesn't work in functional component


When clicking the button, you will see n is getting bigger but the UI remains 1

<script>
let n = 1
function add() {
  console.log(n)
  return ++n
}
export default {
  functional: true,
  render(h, ctx) {
    return (<div>
      <h1>{n}</h1>
      <button onClick={add}>click</button>
    </div>)
  }
}
</script>

Solution

  • Intended Behavior

    This is the intended behavior of functional components and the thing that makes them functional. From the docs:

    ...we can mark components as functional, which means that they’re stateless (no reactive data)

    Since functional components are just functions, they’re much cheaper to render.

    Explanation

    What this means-- and the reason n is not reactive-- is that n is not observable and has no dependency management/watching. This lack of dependency overhead is also the reason for the performance increase of functional components. You get speed at the cost of observability, which is a nice tradeoff if you don't need it. If you do, there would be no reason to use a functional component.

    How to proceed

    So, you could proceed to simply use a non-functional component, or, reason about whether it's possible to subdivide your functional component further and encapsulate only the reactive portions into a non-functional subcomponent.

    Other thoughts

    If you manually added observability to your functional component, you would get the behavior you wanted, though there's no reason to do this over using a non-functional component. Notice the use of observable:

    import Vue from 'vue';
    let state = Vue.observable({n: 1});
    
    function add() {
      console.log(state.n)
      return ++state.n
    }
    
    export default {
      functional: true,
      render(h, ctx) {
        return (<div>
          <h1>{state.n}</h1>
          <button onClick={add}>click</button>
        </div>)
      }
    }
    

    (Note: You can use render functions in normal components as well. I say this just in case you had a misunderstanding that a functional component was required for render functions.)