skip to Main Content

I am trying to inject Switcher10 to the container dom,

render(
    <Switcher10 buttonId={containerid} displayText="AutoReply" isChecked={false} meta={meta}/>,
    container,
  )

Switcher10 looks like this:

import { useState, useEffect } from 'react'

interface Props {
  displayText: string
  buttonId?: number
  isChecked?: boolean
  meta?: string
}


const Switcher10 = (props: Props) => {
  const [isChecked, setIsChecked] = useState(false)
  useEffect(() => {
    if (props.isChecked) setIsChecked(props.isChecked)
  }, [])

  console.log('Switcher10:propsmighthavechanged', props)

  const handleCheckboxChange = () => {
    setIsChecked(!isChecked)
  }

  return (
    <>
      <label className="autoSaverSwitch relative inline-flex cursor-pointer select-none items-center">
        <input
          type="checkbox"
          name="autoSaver"
          className="sr-only"
          checked={isChecked}
          onChange={handleCheckboxChange}
        />
        <span
          className={`slider mr-3 flex items-center rounded-full p-1 duration-200 ${
            isChecked ? 'bg-indigo-500' : 'bg-[#CCCCCE]'
          }`}
        >
          <span
            className={`dot rounded-full bg-white duration-200 ${
              isChecked ? 'translate-x-6' : ''
            }`}
          ></span>
        </span>
      </label>
    </>
  )
}

export default Switcher10

The thing is if the container dom already has Switcher10 it is not even calling the Switcher10 React component.

It is important for me to replace old Switcher10 with new one as the values of props have changed or be able to pass the updated props. Either is fine but neither is happening by simple render().

It is actually going in Switcher10 as console.log('Switcher10:propsmighthavechanged', props) print the new value of props but the react html doesnt rerender with new values.

3

Answers


  1. Chosen as BEST ANSWER

    moved the isChecked changing logic to parent component and passed that function down

    Parent:

    
    const changeIsCheckedPermanently = (meta: string, newValue: boolean) => {
      myMap.set(meta, true)
    }
    
    render(
        <Switcher10 buttonId={containerid} displayText="AutoReply" isChecked={myMap.get(meta)} meta={meta} changeIsCheckedPermanently={changeIsCheckedPermanently}/>,
        container,
      )
    
    
    

    Now child component Switcher10 no longer has a local isChecked variable.

    Switcher10:

    import { useState, useEffect } from 'react'
    
    interface Props {
      displayText: string
      buttonId?: number
      changeIsCheckedPermanently: (meta: string, newValue: boolean) => void
      meta?: string
    }
    
    
    const Switcher10 = (props: Props) => {
    
      const handleCheckboxChange = () => {
        props.changeIsCheckedPermanently(props.meta, !props.isChecked)
      }
    
      return (
        <>
          <label className="autoSaverSwitch relative inline-flex cursor-pointer select-none items-center">
            <input
              type="checkbox"
              name="autoSaver"
              className="sr-only"
              checked={props.isChecked}
              onChange={handleCheckboxChange}
            />
            <span
              className={`slider mr-3 flex items-center rounded-full p-1 duration-200 ${
                props.isChecked ? 'bg-indigo-500' : 'bg-[#CCCCCE]'
              }`}
            >
              <span
                className={`dot rounded-full bg-white duration-200 ${
                  props.isChecked ? 'translate-x-6' : ''
                }`}
              ></span>
            </span>
          </label>
        </>
      )
    }
    
    export default Switcher10
    

  2. You should pass something as the state into the props of Switcher10 so any updates of the props will trigger a re-render of the Switcher10 component.

    In fact, State change is always the primary way to trigger re-render, check the below code (I write it in useState() considering you are mainly using functional components):

    // somewhere above your render()
    const [props, setProps] = useState({
        displayText: '',
        buttonId: '',
        isChecked: false,
        meta: '',
    }) // change if you want any other initial value.
    
    render(
        <Switcher10 buttonId={props.buttonId} displayText="AutoReply" isChecked={props.isChecked} meta={props.meta}/>,
        container,
      )
    

    And when you want to update the values of the props:

    const someAction = () => {
        // do whatever action you need.
        setProps({
            displayText: '[newValue]',
            buttonId: '[newValue]',
            isChecked: true,
            meta: '[newValue]',
        })
    }
    

    Besides, one of the benefits of using hooks in functional components than setState() in class components is that, the state can be interacted with seperately:

    // Through using hooks,
    const [displayText, setText] = useState('');
    const [buttonId, setId] = useState('');
    const [isChecked, setIsChecked] = useState(false);
    const [meta, setMeta] = useState('');
    
    // each value can be updated independently (somewhere in a function, etc.),
    const someAction = () => {
        // do whatever action you need.
        setText('[newValue]');
        setIsChecked(true);
    }
    
    // and thus,
    render(
        <Switcher10 buttonId={buttonId} displayText="AutoReply" isChecked={isChecked} meta={meta}/>,
        container,
    )
    
    Login or Signup to reply.
  3. at first use react memo to skip rendering a component if its props have not changed . ( see the React documentation )
    and then be careful about useState it can cause re rendering (This is written directly into the document)
    and also for manage memory usage useCallback hook see react document.
    (if you need cache the result any were useMemo can help you )
    at end check key of component in parent component because if it changes, the component will render.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search