Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch state updates in useInput callback #581

Merged
merged 1 commit into from
May 1, 2023
Merged

Conversation

vadimdemedes
Copy link
Owner

@vadimdemedes vadimdemedes commented May 1, 2023

Currently, Ink will rerender as soon as state is updated. As a result, if a component has 2 useState hooks and both of them need to be updated at once, it will actually result in 2 rerenders, not 1.

import React, {useState} from 'react';
import {render, useInput, Text} from 'ink';

function Example() {
	const [x, setX] = useState(1);
	const [y, setY] = useState(1);

	useInput(input => {
		if (input === 'i') {
			setX(previousX => previousX + 1);
			setY(previousY => previousY + 1);
		}
	});

	return (
		<Text>
			X = {x} Y = {y}
		</Text>
	);
}

render(<Example/>, {debug: true});

Pressing i will lead to the following output:

X = 1 Y = 1
X = 2 Y = 1
X = 2 Y = 2

Ideally there shouldn't be an intermediate render for "X = 2 Y = 1", which occurs after setX is called and Ink should only rerender after setY.

Fortunately, batchedUpdates function from React reconciler allows Ink to do just that. React DOM automatically batches state updates in event handlers, but Ink doesn't have the concept of DOM events, so this PR uses batchedUpdates to call useInput's callback to simulate React DOM's behavior.

If we run the previous example code in this branch and press i, the output will be:

X = 1 Y = 1
X = 2 Y = 2

Thanks to this, Ink UIs will become much smoother without any changes to their code.

@vadimdemedes vadimdemedes merged commit eed2a11 into master May 1, 2023
6 checks passed
@vadimdemedes vadimdemedes deleted the praiseworthy-hopper branch May 1, 2023 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant