Following is my working application that contains a Search Container, a Sorting Container and a listing Container.
Based on Search and Sort the listing data changes in the listing container.
The application works fine though I noticed in my Search container whenever I am changing the input value in an input box, select component is re rendering and vice versa(check console).
Is there any pattern or modification I can do to minimise the re renders in the application ?
Working Demo - https://ojlrd.csb.app/
Codesandbox - https://codesandbox.io/s/rerender-ojlrd?file=/src/index.js
Code -
Page.js
const Page = () => {
const [pageData, setPageData] = useState({
search: {},
sort: {
sortBy: ''
}
});
const getData = useCallback((type, data) => {
setPageData(prevVal => {
return {
...prevVal,
[type]: {...data}
}
})
}, [setPageData]);
return (
<div className="container">
<SearchContainer getData={getData} />
<SortingContainer getData={getData} />
<ListingContainer urlData={pageData} />
</div>
);
};
export default Page;
SearchContainer.js
const SearchContainer = ({
getData = () => {}
}) => {
const [searchData, setSearchData] = useState({
search1: '',
search2: '13',
search3: '',
search4: '44'
});
useEffect(() => {
getData('search', searchData);
}, [searchData, getData]);
const eventHandler = e => {
setSearchData(prevVal => {
return {
...prevVal,
[e.target.name]: e.target.value
}
})
}
return (
<div className="container-search">
<h3>Search container</h3>
<div className="container-search-actions">
<Input
initialValue=''
label='Input 1'
name="search1"
eventHandler={eventHandler}
/>
<Select
label='Select 2'
name="search2"
options={[
{label: 'Label 11', value: '11'},
{label: 'Label 12', value: '12'},
{label: 'Label 13', value: '13'},
{label: 'Label 14', value: '14'}
]}
selectedValue='13'
eventHandler={eventHandler}
/>
<Input
initialValue=''
label='Input 3'
name="search3"
eventHandler={eventHandler}
/>
<Select
label='Select 4'
name="search4"
options={[
{label: 'Label 41', value: '41'},
{label: 'Label 42', value: '42'},
{label: 'Label 43', value: '43'},
{label: 'Label 44', value: '44'}
]}
selectedValue='44'
eventHandler={eventHandler}
/>
</div>
</div>
)
}
export default SearchContainer;
SortingContainer.js
const SortingContainer = ({
getData = () => {}
}) => {
const [sortData, setSortData] = useState({
sortBy: 'desc'
})
useEffect(() => {
getData('sort', sortData);
}, [sortData, getData]);
const eventHandler = e => {
setSortData(prevVal => {
return {
...prevVal,
[e.target.name]: e.target.value
}
})
}
return (
<div className="container-sorting">
<Select
label='Sort By'
name='sortBy'
options={[
{label: 'Ascending', value: 'asc'},
{label: 'Descending', value: 'desc'}
]}
selectedValue='desc'
eventHandler={eventHandler}
/>
</div>
);
}
export default SortingContainer;
ListingContainer.js
const ListingContainer = ({ urlData }) => {
const createURL = (urlData) => {
const { search, sort } = urlData;
let url = "/api?";
[search, sort].forEach((element) => {
for (const [key, value] of Object.entries(element)) {
url += `&${key}=${value}`;
}
});
return url;
};
return (
<div className="container-listing">
This is a listing container
<p>URL Formed - </p>
<p className="bold">{createURL(urlData)}</p>
</div>
);
};
export default ListingContainer;
1 Answer 1
I was able to resolve this by adding a memo
wrapper around the components' export
statements, then passing in a compare function that returns true
. The components were re-rendering each time the eventHandler
function was re-created when the state of the parent changed on each input.
Since you pass no dynamic data in, there is no reason for these components to re-render except when their own state is updated.
Input.js
...
export default memo(Input, () => true);
Select.js
...
export default memo(Select, () => true);
Explore related questions
See similar questions with these tags.