Programming paradigms at Retool
Learn about the programming styles supported by Retool and their use.
Different programming languages can support one or more styles of programming, known as paradigms. Each paradigm is an approach to writing functional code with programming languages. Some languages can work with multiple paradigms.
Programming paradigms at Retool
Retool app development supports two programming paradigms:
- Declarative reactive programming
- Imperative programming
Both paradigms are applicable at Retool and which you use depends on your objectives. Regardless of your objective, you should strive to write as little code as possible.
Declarative reactive programming
The declarative programming paradigm is an approach that focuses on the end state. You declare the necessary properties rather than construct logic to compute and execute changes. Reactive programming extends this paradigm by way of expressing the desired state through reactionary state using data streams and propagation of change.
Using declarative reactive programming, value dependencies dynamically reflect property changes. Your app constantly reacts to changes without any repeat execution of code to update changes.
Publish-subscribe pattern
Retool enables you to write JavaScript almost anywhere and reference state using {{ }}
notation, such as {{ textInput1.value }}
or {{ query1.data[0].email }}
. Rather than program logic to imperatively publish changes to specific receivers (subscribers), state changes are published for all subscribers to receive. This is referred to as a Publish–subscribe pattern. As state changes, any references automatically and instantly update.
Since you can also write JavaScript expressions within {{ }}
, you can dynamically use conditional logic that processes any time there's a change in state. For example, you can use ternary operators that always use the current state:
{
{
query1.data.length === 0 ? "No results" : query1.data.length + " results";
}
}
Declarative reactive example
The following example demonstrates declarative reactive programming of a user lookup tool. Selecting an email address automatically triggers a query to retrieve data about the associated user. The input components then display the user's first name and last name, and a combination of both displays their full name.
The userLookup
query references the selected email using {{ emailSearch.value }}
and runs automatically whenever an email address is selected—a dedicated event handler is not required.
select * from users
where email = {{ emailSearch.value }}
When run, the query returns the following data for the specified user (e.g., arjun.phillips@example.com
):
{
"id": 4,
"city": "Amsterdam",
"last": "Phillips",
"email": "arjun.phillips@example.com",
"first": "Arjun",
"state": "",
"postal": "1016 BP",
"street": "Herengracht 168",
"country": "Netherlands",
"latitude": "52.36528",
"longitude": "4.89025"
}
The components reference the properties for first and last name, then combine together to display the user's full name. Whenever the query runs, these values update automatically.
Component | Value | Result |
---|---|---|
firstName | {{ query.data.first }} | Arjun |
lastName | {{ query.data.last }} | Phillips |
fullName | {{ firstName.value + ' ' + lastName.value }} | Arjun Phillips |
Imperative programming
The imperative programming paradigm is an approach that focuses on writing and executing code that dictates how state changes. You define the commands that must be explicitly run for changes to occur. No changes are applied until the computational code executes.
An example of imperative programming is through the use of JavaScript code and transformers. You can write JavaScript code that interacts or manipulates data and objects, explicitly changing state. JavaScript code must be triggered to execute and perform the desired actions—no state is changed until this occurs.
Imperative example
The following example demonstrates imperative programming of a user lookup tool. Similar to the declarative reactive programming example, you can select an email address. An event handler is required to trigger the actions and make state changes, which is done using a button.
Change state with methods
You can change the state of many Retool objects, such as components, using built-in JavaScript methods. In this example, a JavaScript query triggers the userLookup
query using trigger()
. Once triggered, the JavaScript query updates the input component values with setValue()
.
await userLookup.trigger();
firstName2.setValue(users.data.first);
lastName2.setValue(users.data.last);
fullName2.setValue(users.data.first + " " + users.data.last);
Since the JavaScript query must be explicitly run, the emailSearch
component has an event handler configured to trigger the JavaScript query on input change.
Compare programming paradigms
Although both examples yield the same results, imperative programming requires significantly more code and configuration. The tool required every action to be explicitly defined and triggered. The declarative reactive programming example did not require any instructions to perform the actions, instead only defining the values for the desired end state. This results in immediate feedback and results of state changes, rather than needing to execute code to reflect state changes.
Since imperative programming has to fully define each action and the state changes to make, it also requires more thorough testing and debugging.
Imperative programming is necessary in some situations, such as running loops to process data in parallel or transforming data. You should use declarative reactive programming for almost all Retool app development, with imperative programming used only where necessary.