javascriptreactjsreact-redux

How to reduce delay while typing in text field in react-redux


// InputField.jsx

import React from 'react'
import { useDispatch } from 'react-redux'
import { setValue } from '../action/setValue.action'
import { Form, FormItem, FormInput } from 'react-blueprint'

export const InputField = (props) => {
    const dispatch = useDispatch()

    const onChange = (e) => {
        const val = e.target.value
        dispatch(setValue('inputField', val)) // dispatches setValue action which updates inputField variable on store
    }

    return (
        <Form>
            <FormItem 
                render={() => 
                    <FormInput 
                        value={props.selector?.inputField}
                        onChange={onChange}
                    />
                }
            />
        </Form>
    )
}

Above is code of my `InputField.jsx`, which dispatches `setValue` action to update the variable on store. On each key stroke dispatch happens and component re renders with updated value which causes lag while typing fast.
// InputField.jsx

import React, from 'react'
import { useDispatch } from 'react-redux'
import { setValue } from '../action/setValue.action'
import { Form, FormItem, FormInput } from 'react-blueprint'

export const InputField = (props) => {
    const dispatch = useDispatch()
    const [input, setInput] = useState('')

    useEffect(() => {
        setTimeout(() => {
            dispatch(setValue('inputField', val)) // dispatches setValue action which updates inputField variable on store
        }, 0)
    }, [input])

    const onChange = (e) => {
        const val = e.target.value
        setInput(val)
    }

    return (
        <Form>
            <FormItem 
                render={() => 
                    <FormInput 
                        value={input}
                        onChange={onChange}
                    />
                }
            />
        </Form>
    )
}

Above is the code that I've tried to reduce the lag and it's working, but I have Edit Button which populates the `inputValue` on store on click and I want to populate the my `input` variable with value which is in store using `setInput`. I tried many ways but it throws error stating `too many re-renders`.
// Edit.jsx

import React from 'react'
import { useDispatch } from 'react-redux'
import { Button } from 'react-blueprint'

export function Edit(item) {
    const dispatch = useDispatch()

    const handleEdit = () => {
        dispatch(setValue('inputField', item.InputField)) // dispatches setValue action which updates inputField variable on store
        window.scrollTo(800, 0)
    }
    
    return (
        <Button
            onClick={handleEdit}
        >
        edit
        </Button>
    )
}

How to handle this case ? Is there any other way to reduce the lag while typing ?
Please help.

Solution

  • I solved the problem using useRef hook and onBlur instead of onChange.

    // InputField.jsx
    
    import React, { useEffect, useRef }from 'react'
    import { useDispatch } from 'react-redux'
    import { setValue } from '../action/setValue.action'
    import { Form, FormItem, FormInput } from 'react-blueprint'
    
    export const InputField = (props) => {
        const dispatch = useDispatch()
        const inputRef = useRef(null)
    
        useEffect(() => {
            inputRef.current.value = props.selector?.inputField
        }, [props.selector?.editClicked]) // sets the value of input field when edit is clicked
    
        const onBlur = (e) => {
            dispatch(setValue('inputField', inputRef.current.value)) // dispatches setValue action which updates inputField variable on store
        }
    
        return (
            <Form>
                <FormItem 
                    render={() => 
                        <FormInput 
                            ref={inputRef}
                            onBlur={onBlur}
                        />
                    }
                />
            </Form>
        )
    }
    

    // Edit.jsx
    
    import React from 'react'
    import { useDispatch } from 'react-redux'
    import { Button } from 'react-blueprint'
    
    export function Edit(item) {
        const dispatch = useDispatch()
    
        const handleEdit = () => {
            dispatch(setValue('inputField', item.InputField)) // dispatches setValue action which updates inputField variable on store
            setTimeOut(() => {
                window.scrollTo(800, 0)
                dispatch(toggleEditclicked()) // toggles editClicked variable on store when edit is clicked
            })
            
        }
        
        return (
            <Button
                onClick={handleEdit}
            >
            edit
            </Button>
        )
    }