Render Props in React
Learn how to use render props in React so that we can act on that data directly instead of having to carry many stateful variables in the app component.
So far, all of our application examples have a single functionality, either searching, sorting, or filtering. But what if we want to have search, sort, and filter abilities acting on our data in combination? Unfortunately, if we combine the code for search, sorting, and filtering, our App.tsx
becomes bloated and hard to understand.
function App() {const [query, setQuery] = useState<string>("");const [showPeople, setShowPeople] = useState<boolean>(false);const [widgetSortProperty, setWidgetSortProperty] = useState<ISorter<IWidget>>({ property: "title", isDescending: true });const [widgetFilterProperties, setWidgetFilterProperties] = useState<Array<IFilter<IWidget>>>([]);const [peopleSortProperty, setPeopleSortProperty] = useState<ISorter<IPerson>>({ property: "firstName", isDescending: true });const [peopleFilterProperties, setPeopleFilterProperties] = useState<Array<IFilter<IPerson>>>([]);const buttonText = showPeople ? "Show widgets" : "Show people";return (<><buttonclassName="btn btn-primary"onClick={() => setShowPeople(!showPeople)}>{buttonText}</button><SearchInputsetSearchQuery={(query) => {setQuery(query);}}/>{!showPeople && (<><h2>Widgets:</h2><SorterssetProperty={(propertyType) => {setWidgetSortProperty(propertyType);}}object={widgets[0]}/><br /><Filtersobject={widgets[0]}properties={widgetFilterProperties}onChangeFilter={(property) => {const propertyMatch = widgetFilterProperties.some((widgetFilterProperty) =>widgetFilterProperty.property === property.property);const fullMatch = widgetFilterProperties.some((widgetFilterProperty) =>widgetFilterProperty.property === property.property &&widgetFilterProperty.isTruthySelected ===property.isTruthySelected);if (fullMatch) {setWidgetFilterProperties(widgetFilterProperties.filter((widgetFilterProperty) =>widgetFilterProperty.property !== property.property));} else if (propertyMatch) {setWidgetFilterProperties([...widgetFilterProperties.filter((widgetFilterProperty) =>widgetFilterProperty.property !== property.property),property,]);} else {setWidgetFilterProperties([...widgetFilterProperties,property,]);}}}/>{widgets.filter((widget) =>genericSearch(widget, ["title", "description"], query, false)).filter((widget) => genericFilter(widget, widgetFilterProperties)).sort((a, b) => genericSort(a, b, widgetSortProperty)).map((widget) => {return <WidgetRenderer {...widget} />;})}</>)}{showPeople && (<><h2>People:</h2><SorterssetProperty={(propertyType) => {setPeopleSortProperty(propertyType);}}object={people[0]}/><Filtersobject={people[0]}properties={peopleFilterProperties}onChangeFilter={(property) => {const propertyMatch = peopleFilterProperties.some((peopleFilterProperty) =>peopleFilterProperty.property === property.property);const fullMatch = peopleFilterProperties.some((peopleFilterProperty) =>peopleFilterProperty.property === property.property &&peopleFilterProperty.isTruthySelected ===property.isTruthySelected);if (fullMatch) {setPeopleFilterProperties(peopleFilterProperties.filter((peopleFilterProperty) =>peopleFilterProperty.property !== property.property));} else if (propertyMatch) {setPeopleFilterProperties([...peopleFilterProperties.filter((peopleFilterProperty) =>peopleFilterProperty.property !== property.property),property,]);} else {setPeopleFilterProperties([...peopleFilterProperties,property,]);}}}/>{people.filter((person) =>genericSearch(person,["firstName", "lastName", "eyeColor"],query,false)).filter((person) => genericFilter(person, peopleFilterProperties)).sort((a, b) => genericSort(a, b, peopleSortProperty)).map((person) => {return <PeopleRenderer {...person} />;})}</>)}</>);}export default App;
In addition to being difficult to understand, there is another problem with the code we’ve written so far—at least with using the object
prop for sorting and filtering. In our examples, widgets
and people
are static lists. But, when we load this data in an API, we can’t guarantee we’ll always have an entity within widget[0]
and people[0]
. Either could be an empty array, or depending on the API ...