Reactive Props V2 #71

Merged
thesabinelim merged 1 commits from reactive-props-2 into master 2023-05-13 23:16:54 +08:00
thesabinelim commented 2023-05-13 21:04:05 +08:00 (Migrated from github.com)

The original reactive props system was based on a naive implementation (a hard-coded pattern match for the shared and props tables in a prop and a metatable to detect reads/writes on the shared table) that was proving difficult to extend further. This PR rebuilds the reaction system to be based on a new primitive, basalt.reactive, which is not coupled to the environment. It also does away with the naive pattern matching. Any global variable can now be accessed in a reactive prop. Additionally, reactive props are now full Lua expressions, which are computed to return a value. This makes it possible to do things like this:

<script>
  local basalt = require("basalt")
  getCount, setCount = basalt.reactive(0)
</script>

<button text={"Times clicked: " .. getCount()}>
  <onClick>
    setCount(getCount() + 1)
  </onClick>
</button>

<label text={"Times clicked * 2 = " .. getCount() * 2} />

Internally, this works in much the same way that Signals work in Solid.js. We populate a list of observers for a reactive value on the first pass render, based on calls to their respective get functions. A subsequent call of the set function will then update all these observers.

Other changes

  • Removed the shared table, there's no need for it anymore
  • Removed basalt from layout envs, because if it's needed it can just be imported. Unnecessary global variables are bad!
  • Also removed the main variable from layouts loaded into a Frame
The original reactive props system was based on a naive implementation (a hard-coded pattern match for the shared and props tables in a prop and a metatable to detect reads/writes on the shared table) that was proving difficult to extend further. This PR rebuilds the reaction system to be based on a new primitive, `basalt.reactive`, which is not coupled to the environment. It also does away with the naive pattern matching. Any global variable can now be accessed in a reactive prop. Additionally, reactive props are now **full Lua expressions**, which are computed to return a value. This makes it possible to do things like this: ```xml <script> local basalt = require("basalt") getCount, setCount = basalt.reactive(0) </script> <button text={"Times clicked: " .. getCount()}> <onClick> setCount(getCount() + 1) </onClick> </button> <label text={"Times clicked * 2 = " .. getCount() * 2} /> ``` Internally, this works in much the same way that Signals work in Solid.js. We populate a list of observers for a reactive value on the first pass render, based on calls to their respective get functions. A subsequent call of the set function will then update all these observers. Other changes - Removed the shared table, there's no need for it anymore - Removed basalt from layout envs, because if it's needed it can just be imported. Unnecessary global variables are bad! - Also removed the main variable from layouts loaded into a Frame
Sign in to join this conversation.
No description provided.