mirror of
https://github.com/lockin-bot/react-telegram.git
synced 2026-01-13 07:09:56 +08:00
fix: input not persist after rerender
This commit is contained in:
@@ -15,7 +15,8 @@
|
||||
"Bash(git commit:*)",
|
||||
"Bash(bun tsc:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(bun x tsc:*)"
|
||||
"Bash(bun x tsc:*)",
|
||||
"Bash(bun:*)"
|
||||
],
|
||||
"deny": []
|
||||
}
|
||||
|
||||
@@ -324,4 +324,60 @@ describe('Telegram Reconciler', () => {
|
||||
container.inputCallbacks[0]?.callback('test message');
|
||||
expect(onSubmit).toHaveBeenCalledWith('test message');
|
||||
});
|
||||
|
||||
it('should preserve input elements across re-renders', async () => {
|
||||
const { container, render, clickButton } = createContainer();
|
||||
|
||||
const App = () => {
|
||||
const [mode, setMode] = useState<'normal' | 'secret'>('normal');
|
||||
const handleNormal = vi.fn();
|
||||
const handleSecret = vi.fn();
|
||||
|
||||
return (
|
||||
<>
|
||||
{mode === 'normal' ? (
|
||||
<input onSubmit={handleNormal} />
|
||||
) : (
|
||||
<input onSubmit={handleSecret} autoDelete />
|
||||
)}
|
||||
<row>
|
||||
<button onClick={() => setMode(m => m === 'normal' ? 'secret' : 'normal')}>
|
||||
Toggle
|
||||
</button>
|
||||
</row>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
render(<App />);
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
|
||||
// Initial state - normal mode
|
||||
expect(container.root.children[0]).toEqual({
|
||||
type: 'input',
|
||||
onSubmit: expect.any(Function),
|
||||
autoDelete: undefined
|
||||
});
|
||||
expect(container.inputCallbacks).toHaveLength(1);
|
||||
expect(container.inputCallbacks[0]?.autoDelete).toBeUndefined();
|
||||
|
||||
// Toggle to secret mode
|
||||
clickButton('0-0');
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
|
||||
// Should still have input but with different props
|
||||
expect(container.root.children[0]).toEqual({
|
||||
type: 'input',
|
||||
onSubmit: expect.any(Function),
|
||||
autoDelete: true
|
||||
});
|
||||
expect(container.inputCallbacks).toHaveLength(1);
|
||||
expect(container.inputCallbacks[0]?.autoDelete).toBe(true);
|
||||
|
||||
// Verify the callback works
|
||||
container.inputCallbacks[0]?.callback('test');
|
||||
|
||||
// Verify the structure is correct
|
||||
expect(container.inputCallbacks[0]).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -215,9 +215,31 @@ const hostConfig: ReactReconciler.HostConfig<
|
||||
) {
|
||||
// Deep clone but preserve functions
|
||||
const clone = JSON.parse(JSON.stringify(instance));
|
||||
if (instance.onClick) {
|
||||
clone.onClick = instance.onClick;
|
||||
|
||||
// Update with new props for specific instance types
|
||||
if (instance.type === 'button') {
|
||||
clone.onClick = newProps.onClick || instance.onClick;
|
||||
// Update button text from new props if available
|
||||
if (newProps.children !== undefined) {
|
||||
let buttonText = '';
|
||||
if (typeof newProps.children === 'string') {
|
||||
buttonText = newProps.children;
|
||||
} else if (Array.isArray(newProps.children)) {
|
||||
buttonText = newProps.children.map((child: any) =>
|
||||
typeof child === 'string' ? child : String(child)
|
||||
).join('');
|
||||
} else if (newProps.children != null) {
|
||||
buttonText = String(newProps.children);
|
||||
}
|
||||
clone.text = buttonText;
|
||||
}
|
||||
} else if (instance.type === 'input') {
|
||||
clone.onSubmit = newProps.onSubmit;
|
||||
clone.autoDelete = newProps.autoDelete;
|
||||
} else if (instance.type === 'link') {
|
||||
clone.href = newProps.href || instance.href;
|
||||
}
|
||||
|
||||
// Handle children based on keepChildren flag
|
||||
if (clone.children && Array.isArray(clone.children)) {
|
||||
if (keepChildren) {
|
||||
|
||||
Reference in New Issue
Block a user