DEV Community

Kwesikwaa Hayford
Kwesikwaa Hayford

Posted on

React js: Avoid Needless Rebuilds

useState is the react ecosystem's way of rebuilding or reactivity but this triggers a rebuild of the entire UI. In Vue, reactivity is limited to variables and the component that parents them.

Using useState in some cases is very important, but in some other cases it may be detrimental and must be used strategically.

There are ways to mitigate this problem but these are my two personal favourites. One route is to build separate components for things that change and allow the useState to happen locally, only in those component without affecting the entire UI and the second is to resort to the signals package for reactivity.

Building separate components
React Native example:
You are building a chat app and therefore has to make sure that the Text Input has onChangedText property assigned to a function which has a useState to allow binding. This is simple but it also means on every key that is entered in the textbox, the entire interface rebuilds. To avoid this, simply build the Text Input and the the send button as a separate component. That component is then imported and used in the rest of the app. This means the useState happens only in that component while the parent component only receives the values from the child's props without rebuilding the parent component.

export default function InputText({send}){
    const [text,setText] = useState('')
    console.log("child rebuilding as proof...")
    return (
        <View>
            <TextInput value= {text} placeholder='Enter Prompt' placeholderTextColor="white" multiline onChangeText={setText}/>
            <TouchableOpacity onPress={()=>{if(text)send(text);setText('')}}>
                <Text> send</Text>
            </TouchableOpacity>

        </View>
    )
}

export default function Parent(){
    const send = (val){
        console.log(`value is ${val}`)
    }
    console.log('parent rebuilding for proof....)
    return(
        <View>
            <InputText send={send} />
        </View>
    )
}
Enter fullscreen mode Exit fullscreen mode

In the above example, you will realize that "parent rebuilding for proof" is logged only once while "child rebuilding for proof..." gets to be logged whenever a key is punched. Clean and simple. rebuilding only happens in that small component.

Using React Signals
React Example:
This code demonstrate how a pop up modal results in a rebuild of both the parent and modal components whenever the modal is toggled.

import { useState } from 'react'

export function PopUp({prop,emit}){
    console.log('Rendering Popup......')
    return (
        <>
            {prop && <div style={{position:"relative"}}>
                <p>This is the popup</p>
                <p>
                    And this is the proped data {prop}
                </p>
                <button style={{background:"red", color:"white"}}
                    onClick={()=>emit(false)}
                >
                    close
                </button>
            </div> }
        </>
    )
}

export default function Parent(){
    console.log('Rendering parent...')
    const [dataToPopUp, setPropData] = useState(false)
    return(
        <>
         <button onClick={()=>setPropData(true)}
         >
             Show PopUp
         </button>
         <PopUp prop={dataToPopUp} emit={(val)=>setPropData(val)}/>
        </>
    )
}
Enter fullscreen mode Exit fullscreen mode

Below is a signals approach. It utilises a global signals variable which can be accessed from any component

import {signal} from '@preact/signals-react'

const dataToPopUp = signal(null)

export function PopUp(){
    console.log('Rendering Popup......')
    return (
        <>

            {dataToPopUp.value && <div style={{position:"relative"}}>
                <p>This is the popup</p>
                <p>
                    And this is the proped data {dataToPopUp.value}
                </p>
                <button style={{background:"red", color:"white"}}
                    onClick={()=>dataToPopUp.value = null}
                >
                    close
                </button>
            </div> }
        </>
    )
}

export default function Parent(){
    console.log('Rendering parent...')
    return(
        <>
         <button onClick={()=>dataToPopUp.value = 'hello'}
         >
             Show PopUp SIGNALS
         </button>
         <PopUp/>
        </>
    )
}
Enter fullscreen mode Exit fullscreen mode

Both approaches rebuilds only the child component. Efficient and Done !

Top comments (0)