Skip to content

Conversation

@SandyTao520
Copy link
Contributor

In React 19 support PR #719 , logic for marking Static as dirty was removed. I'm not sure why this was removed, but it prevents the Static component from being updated when new components are added to items.

I see React removed prepareUpdate() and asked developers to do the preparation in commitUpdate, however, the commitUpdate method doesn't provide root node. The solution is to add a global variable tracking the root node.

@SandyTao520 SandyTao520 marked this pull request as ready for review June 11, 2025 20:53
@sindresorhus
Copy link
Collaborator

@msmps Could you help review?

@msmps
Copy link
Contributor

msmps commented Jun 13, 2025

I'm vacationing until 19/06 but do you have a minimal reproduction for this issue @SandyTao520 ? I'm struggling to reproduce this using the tests / examples provided

@SandyTao520
Copy link
Contributor Author

SandyTao520 commented Jun 13, 2025

Hi @msmps, thanks for taking a look. Yeah this is tricky - it only happens when trying to update Static children in a async/await operation.

I wrote this example that you can press Enter to read files in the current directory, it will print out all the file names and sizes. Note that there is await before setFiles(). If you run this example in master branch, pressing enter won't re-render Static, but if you switch to my branch it updates properly.

Let me know if you think this is due to a different root cause.

import React from 'react';
import { Box, Text, render, Static, useInput } from '../../src/index.js';
import { readFile, readdir } from 'node:fs/promises';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

function Example() {
	const [files, setFiles] = React.useState<
		Array<{
			id: number;
			title: string;
			fileSize?: number;
		}>
	>([]);
	const [isRunning, setIsRunning] = React.useState(false);

	useInput(async (_, key) => {
		if (key.return && !isRunning) {
			setIsRunning(true);

			// Get current directory where static.tsx is located
			const currentDir = dirname(fileURLToPath(import.meta.url));
			const files = await readdir(currentDir);

			for (const filename of files) {
				const filePath = resolve(currentDir, filename);
				const fileContent = await readFile(filePath, 'utf8');
				const fileSize = fileContent.length;

				setFiles(previousFiles => [
					...previousFiles,
					{
						id: previousFiles.length,
						title: `Analyzed ${filename}`,
						fileSize,
					},
				]);
			}

			setIsRunning(false);
		}
	});

	return (
		<>
			{!isRunning && (
				<Box>
					<Text>Press Enter to start reading files...</Text>
				</Box>
			)}

			<Static key="static" items={files}>
				{file => (
					<Box key={file.id}>
						<Text color="green">
							 {file.title}
							{file.fileSize && <Text dimColor> ({file.fileSize} bytes)</Text>}
						</Text>
					</Box>
				)}
			</Static>

			<Box marginTop={1}>
				<Text dimColor>
					{isRunning ? 'Analyzing files...' : `Completed ${files.length} file analysis tasks`}
				</Text>
			</Box>
		</>
	);
}

render(<Example />);

@cperry-goog
Copy link

@msmps are you back in today and possible to check on this?

@torbjon
Copy link

torbjon commented Jun 24, 2025

was spend last two days, fighting with Static not randomly rendering items
this pr fix it, thanks

@msmps
Copy link
Contributor

msmps commented Jun 25, 2025

@sindresorhus LGTM!

@sindresorhus sindresorhus merged commit 03872b2 into vadimdemedes:master Jun 25, 2025
1 check passed
@sindresorhus
Copy link
Collaborator

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.

5 participants