Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with memo #416

Open
mvillafuertem opened this issue Sep 7, 2020 · 5 comments
Open

Issue with memo #416

mvillafuertem opened this issue Sep 7, 2020 · 5 comments
Labels

Comments

@mvillafuertem
Copy link

mvillafuertem commented Sep 7, 2020

Hi all, I am experiencing component refresh even though I am using React.memo. Am I wrong about something?

Here my use case, see Memorize and open console https://mvillafuertem.github.io/zio-react/hooks/

@react object MemorizeApp {

  type Props = Unit

  val component: FunctionalComponent[Props] = FunctionalComponent[Props] { _ =>
    val (counter, increment, _, _) = useCounter(10)
    val (show, setShow)            = useState(true)

    val handleClick: js.Function1[SyntheticMouseEvent[TagElement#RefType], Unit] =
      (_: SyntheticMouseEvent[TagElement#RefType]) => setShow(!show)

    Fragment(
      h1("Memorize"),
      h3(Small(counter)),
      button(className := "btn btn-success", onClick := increment)("+1"),
      button(className := "btn btn-outline-success ml-3", onClick := handleClick)(s"Show/Hide ${js.JSON.stringify(show)}")
    )

  }

}


@react object Small {

  case class Props(value: Int)

  val component: FunctionalComponent[Props] = React.memo(FunctionalComponent[Props] {
    case Props(value) =>
      println("Refresh Component")
      small(value)
  })

}
@mvillafuertem
Copy link
Author

Hi @ramnivas, maybe you know why this happens. Thanks in advice!

@ramnivas
Copy link
Contributor

ramnivas commented Sep 7, 2020

By default React performs shallow compare of the props (and for Option props, shallow comparison result in not-equal). So try passing the second argument to it (something like (oldProps: Props, newProps: Props) => oldProps == newProps)

@mvillafuertem
Copy link
Author

@ramnivas something strange is happening to me, the same js code works without use comparison. it's something special from slinky?

https://stackblitz.com/edit/react-sl3mi8

import React from "react";
import "./style.css";

//import { useState } from 'react';
const { useState } = React;

export const Small = React.memo(({value}) => {
  console.log("Refresh Component")
  return (
    <small>{ value }</small>
  )
})

export const MemorizeApp = () => {
  const [count, setCount] = useState(0)
  const [show, setShow] = useState(true)

  return (
    <div>
      <h1><Small value={ count } /></h1>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
       <button onClick={() => setShow(!show)}>
        Show {JSON.stringify(show)}
      </button>
    </div>
  )
}



export default function App() {
  return (<MemorizeApp />
  );
}

@mvillafuertem
Copy link
Author

mvillafuertem commented Sep 8, 2020

How would it be solved in this use case?

Here my real use case, see Father and open console https://mvillafuertem.github.io/zio-react/hooks/

@react object CallbackHookApp {

  type Props = Unit

  val component: FunctionalComponent[Props] = FunctionalComponent[Props] { _ =>
    val (counter, setCounter) = useState[Int](0)


    val incrementCallback: () => Unit =
      useCallback(() => setCounter(counter => counter + 1), Seq(setCounter))

    Fragment(
      h1("CallbackHookApp"),
      h3(counter),
      ShowIncrement(incrementCallback)
    )
  }

}


@react object ShowIncrement {

  case class Props(increment: () => Unit)

  val component: FunctionalComponent[Props] = React.memo(
    FunctionalComponent[Props] {
      case Props(increment) =>
        println("Refresh Component, only show when the props changes")
        button(className := "btn btn-success", onClick := increment)("+1")

    },
    (oldProps: Props, newProps: Props) => oldProps.increment eq newProps.increment
  )

}

@evbo
Copy link

evbo commented Sep 11, 2022

this is such a great reference example on SyntheticMouseEvent as well as React.memo, I keep coming back to it!

@mvillafuertem call me lazy, but I usually solve issues like this with a surrogate refresh_id that dictates when the component should re-render, rather than relying on equality checks of something like functions.

So essentially add a prop called refresh_id or something and increment it by 1 every time you want to actually change increment, then in your React.memo use the surrogate id as the check.

There might be a way to compare functions in ScalaJS, but... laziness :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants