Skip to content

Instantly share code, notes, and snippets.

@r0b0t3d
Created July 10, 2021 09:06
Show Gist options
  • Save r0b0t3d/db629f5f4e249c7a5b6a3c211f2b8aa8 to your computer and use it in GitHub Desktop.
Save r0b0t3d/db629f5f4e249c7a5b6a3c211f2b8aa8 to your computer and use it in GitHub Desktop.
Use of useCallback and useMemo

1. Use

1.1. in callback

const handlePress = useCallback(() => {
	// handle press
}, [])

Good πŸ‘

<Button onPress={handlePress} />

Not good πŸ‘Ž

<Button onPress={() => handlePress()} />

1.2. use curry functions when possible

<FlatList
	renderItem={renderItem}
/>

Good πŸ‘

const handlePress = useCallback((item) => () => {
	// handle item press
}, [])

const renderItem = ({ item }) => {
	return <SomeComponent onPress={handlePress(item)} />
}

Not good πŸ‘Ž

const handlePress = useCallback((item) => {
	// handle item press
}, [])

const renderItem = ({ item }) => {
	return <SomeComponent onPress={() => handlePress(item)} />
}

2. No use

2.1. FlatList's render methods

<FlatList
	renderItem={renderItem}
	ListHeaderComponent={renderHeader}
/>

Good πŸ‘

const renderItem = ({ item }) => {
	return <SomeComponent onPress={handlePress(item)} />
}

const renderHeader = () => {
	return <SomeComponent />
}

Not good πŸ‘Ž

const renderItem = useCallback(({ item }) => {
	return <SomeComponent onPress={handlePress(item)} />
}, []);

const renderHeader = useCallback(() => {
	return <SomeComponent />
}, []);

2.2. Render item in array

const data = [];
return (
	<View>
		{data.map(renderItem)}
	<View>
)

Good πŸ‘

function renderItem() {
	return <SomeComponent />
}

Not good πŸ‘Ž

const renderItem = useCallback(() => {
	return <SomeComponent />
}, [])

1. Expensive calculations

function SomeComponent({ todos }) {
	const completedCount = ...
	
	return (
		<View>
			<Text>{`Completed: ${completedCount}`}</Text>
		</View>
	)
}

Good πŸ‘

const completedCount = useMemo(() => todos.reduce((acc, item) => {
		if (item.isCompleted) {
			return acc + 1,
		}
		return acc
	}, 0)
}, [todos])

Not good πŸ‘Ž

const completedCount = todos.reduce((acc, item) => {
	if (item.isCompleted) {
		return acc + 1,
	}
	return acc
}, 0)

2. Use as dependency in another hook

function SomeComponent({ todos }) {
	const completedItems = [...]

	const handleSubmit = useCallback(() => {
		// handle data submit
	}, [completedItems]);

	return (
		<View>
			{completedItems.map(renderItem)}
			<Pressable onPress={handleSubmit}>
				<Text>Submit</Text>
			</Pressable>
		</View>
	)
}

Good πŸ‘

const completedItems = useMemo(() => todos.filter(item => item.isCompleted), [todos]);

Not good πŸ‘Ž

const completedItems = todos.filter(item => item.isCompleted);
@GaylordP
Copy link

Hello,

Are you sure what you say under "2.1. FlatList's render methods" ?

Many sites recommend using useCallback() for renderItem() and even keyExtractor()

Example : https://dev.to/ltsharma/performance-optimisation-react-native-with-hooks-a77

What is your opinion on the matter? Maybe it is an entry error ^^

Thanks in advance

@dentemm
Copy link

dentemm commented Feb 16, 2022

@GaylordP I also did some research on this, and come to the same conclusion. It's a bad idea to use useCallback for renderItem. First of all it's completely unnecessary since VirtualizedList is taking care of referential equality by itself. And secondly: by using useCallback you are executing more code and even preventing garbage collection. It's never a good idea to use useCallback for render functions.

@ashisharora1692
Copy link

@GaylordP if I use currying as you said in 1.2 then component will rerender everytime because inner function will be recreated everytime and props will be changed.i tried few days ago before reading above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment