Setup#
To get started building the application, we'll need to bootstrap it with Create React App. Create React App is a tool that helps initialize React projects and it's one of the quickest ways to get started writing a React application.
Start by making a myapp
directory and changing into that directory:
mkdir myapp
cd myapp
Next, initialize a git repository within that directory.
git init
Then run the npx
command to generate a new React application using Create React App in a folder called client
. We'll use the typescript
template, and force the use of npm
since that's what our remote server will use.
npx create-react-app client --template typescript --use-npm
cd client
(We do it this way, i.e. myapp/client, to get ready for the full application later.)
Finally, let's add some additional dependencies, react-querybuilder
and node-sass
.
npm i react-querybuilder node-sass@^4.14.1
Once that command is finished, delete the unnecessary files:
src/setupTests.ts
src/App.test.tsx
src/logo.svg
src/reportWebVitals.ts
public/favicon.ico
public/logo*.png
public/manifest.json
public/robots.txt
Remove references to reportWebVitals.ts
from index.tsx
. Also remove references to manifest.json
, logo*.png
, and favicon.ico
from index.html
.
Rename App.css
to App.scss
and replace the contents with this:
@import "~react-querybuilder/dist/query-builder.scss";
Change the corresponding import in App.tsx
.
- import "./App.css"
+ import "./App.scss"
We'll also modify index.css
to add a little bit of margin to the page.
/* index.css */
body {
- margin: 0;
+ margin: 1rem;
}
Adding the query builder#
Now we're ready to create a query builder. You can do this in just a few lines of code. Import QueryBuilder
from react-querybuilder
and replace the return
statement in App.tsx
with the following code:
import QueryBuilder from "react-querybuilder";
// ...
return (
<QueryBuilder
fields={[{ name: "test", label: "Test" }]}
onQueryChange={(q) => console.log(q)}
/>
);
This code will display the query builder in the application and allow the user to create rules and groups of rules, but with only one field (don't worry, we'll fix that in the next lesson). It will also log the internal query representation to the console.
Now start the application:
npm start
View the app at http://localhost:3000/ to make sure it's working.
Making a controlled component#
What we have now is called an uncontrolled component, which means you can't control the behavior of the component with code. The state of the query builder is managed internally and we have no way to capture the inputs and outputs.
We want a controlled component, so we'll add the query
and onQueryChange
props into the App
function in App.tsx
, using a state variable to control the query. The state variable will need to be of type RuleGroupType
, which we can import from react-querybuilder
.
import { useState } from "react";
import QueryBuilder, { RuleGroupType } from "react-querybuilder";
// ...
const [query, setQuery] = useState<RuleGroupType>({
id: "root",
combinator: "and",
rules: [],
});
return (
<QueryBuilder
fields={[{ name: "test", label: "Test" }]}
onQueryChange={(q) => setQuery(q)}
query={query}
/>
);
Since we're no longer printing the query out to the console, and we'd still like to see the output, we can print the query out to the screen in JSON and SQL formats by using the formatQuery
function provided by react-querybuilder
. We'll discuss this function in more detail in a later lesson.
import React, { useState } from "react";
import QueryBuilder, { formatQuery, RuleGroupType } from "react-querybuilder";
function App() {
const [query, setQuery] = useState<RuleGroupType>({
id: "root",
combinator: "and",
rules: [],
});
return (
<>
<QueryBuilder
fields={[{ name: "test", label: "Test" }]}
query={query}
onQueryChange={(q) => setQuery(q)}
/>
<pre>{formatQuery(query, "sql")}</pre>
<pre>{formatQuery(query, "json")}</pre>
</>
);
}
export default App;