Skip to content

Instantly share code, notes, and snippets.

@omahlama
Last active November 26, 2020 08:44
Show Gist options
  • Save omahlama/6623df834d1785c7c4222b568b848adc to your computer and use it in GitHub Desktop.
Save omahlama/6623df834d1785c7c4222b568b848adc to your computer and use it in GitHub Desktop.
Pattern for encapsulating logic in react hooks and components

Pattern for encapsulating logic

I'm trying to figure out the best way to extract functionality from a big component into separate files, so that it would be easier to read and maintain. I think it makes a lot of sense to pair the logic and component into the same file, since they are deeply coupled together anyway.

I simplified the example here, but please imagine that both the custom hook logic and the component are complicated enough that it makes sense to not just put them directly inside the List component.

Version 1 is the traditional way of doing this, version 2 is what I came up with. What I like about version 2 is that it keeps the internals of the hook hidden and the api to the the component using it is much cleaner. Are there any downsides?

Edit

I added option 3, where we expose props together instead of 1 by 1. Thanks Alexander for the suggestion.

import React from 'react';
import { DataTable } from './DataTable';
import { useSearch, SearchInput } from './useSearch1';
const List1 = ({ data }) => {
const { searchTerm, setSearchTerm, filteredData } = useSearch(data);
return <div>
<SearchInput value={searchTerm} onChange={setSearchTerm} />
<DataTable data={filteredData} />
</div>
}
export default List1;
import React from 'react';
import { DataTable } from './DataTable';
import { useSearch } from './useSearch2';
const List2 = ({ data }) => {
const { filteredData, SearchInput } = useSearch(data);
return <div>
<SearchInput />
<DataTable data={filteredData} />
</div>
}
export default List2;
import React from 'react';
import { DataTable } from './DataTable';
import { useSearch, SearchInput } from './useSearch3';
const List3 = ({ data }) => {
const { searchInputProps, filteredData } = useSearch(data);
return <div>
<SearchInput {...searchInputProps} />
<DataTable data={filteredData} />
</div>
}
export default List1;
import React, {useState} from 'react';
export const useSearch = (data) => {
const [searchTerm, setSearchTerm] = useState('');
const filteredData = data.filter(item => searchTermMatches(item, searchTerm);
return { searchTerm, setSearchTerm, filteredData }
}
export const SearchInput = ({value, onChange}) => (
<input value={value} onChange={e => onChange(e.currentTarget.value} />
)
import React, {useState} from 'react';
export const useSearch = (data) => {
const [searchTerm, setSearchTerm] = useState('');
const filteredData = data.filter(item => searchTermMatches(item, searchTerm);
const SearchInput = () => {
<input value={searchTerm} onChange={e => setSearchTerm(e.currentTarget.value} />
}
return { filteredData, SearchInput }
}
import React, {useState} from 'react';
export const useSearch = (data) => {
const [searchTerm, setSearchTerm] = useState('');
const filteredData = data.filter(item => searchTermMatches(item, searchTerm);
const searchInputProps = {
value: searchTerm,
onChange: setSearchTerm,
};
return { searchInputProps, filteredData }
}
export const SearchInput = ({value, onChange}) => (
<input value={value} onChange={e => onChange(e.currentTarget.value} />
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment