Skip to main content
Version: v7

Common mistakes

Custom component as closure

When defining custom components for React Query Builder, do not define them within the body of another function component like this:

App.jsx
const App = () => {
// Other stuff ...

const CustomValueEditor = props => {
// Custom logic here ...
return <input />;
};

return (
<QueryBuilder
fields={fields}
query={query}
handleOnChange={q => setQuery(q)}
controlElements={{
valueEditor: CustomValueEditor,
}}
/>
);
};

This will almost certainly lead to undesirable behavior such as the value editor losing focus after each keystroke. This happens because the CustomValueEditor component is being redefined each time the App component renders. To fix the problem, move the custom component declaration outside of the other function component (it can still be in the same file, just not within the function body):

App.jsx
const CustomValueEditor = props => {
// Custom logic here ...
return <input />;
};

const App = () => {
// Other stuff ...

return (
<QueryBuilder
fields={fields}
query={query}
handleOnChange={q => setQuery(q)}
controlElements={{
valueEditor: CustomValueEditor,
}}
/>
);
};

A similar mistake that leads to the same problems is declaring arrow functions that render components inside the JSX syntax. In the code below, CustomValueEditor is correctly defined outside the body of App, but an arrow function that renders CustomValueEditor is assigned to valueEditor instead of the CustomValueEditor component itself. This causes a new function component to be created on every render.

App.jsx
const CustomValueEditor = props => {
// Custom logic here ...
return <input />;
};

const App = () => {
// Other stuff ...

return (
<QueryBuilder
fields={fields}
query={query}
handleOnChange={q => setQuery(q)}
controlElements={{
// Don't do this:
valueEditor: props => <CustomValueEditor {...props} />,
// Do this instead:
// valueEditor: CustomValueEditor,
}}
/>
);
};