🙃

Reactのコンポーネントに引数付きの関数を渡したら思ってたのと違う挙動になった

2024/10/11に公開2

こんにちは!
普段Webアプリの開発を行っているn-kokiと申します。

タイトルの通り、Reactのコンポーネントにpropsで引数付きの関数を渡したら、思っていたのと違う挙動をしたので、その内容と解決策について紹介します。

何がしたかったのか

Reactのpropsで変数の他に、関数も渡すことができることは、多くの方がご存じかと思います。私はこれを使って、ボタンのコンポーネントに対してonClickで発火する関数を渡そうとしました。引数の無い関数では思い通りに動くのですが、引数をつけるとボタンを押さずともページが読み込まれた瞬間に実行されていしました...

App.js
import Button from './Button'

function App() {
  const func1 = () => {
    alert("ボタンが押されたよ!")
  }

  const func2 = ( data ) => {
    alert("ボタンが押されたよ!\n" + data + "っていうデータも受け取ったよ!" )
  }

  return (
    <div className="App">
      {/* ↓ 動画では使わない方にコメントをしています。 */}
      <Button func={ func1 }></Button>
      <Button func={ func2("data") }></Button>
      <a href="">
        <button className="button">リロード</button>
      </a>
    </div>
  )
}

export default App
Button.jsx
const Button = ( props ) => {
  return (
    <button className="button" onClick={ props.func }>ボタンを押してね!</button>
  )
}

export default Button

引数なしの場合(思い通りにいった)


動画のように引数なしの場合は、リロードしても特に何も起こらず、左のボタンを押すと関数が実行されます。

引数ありの場合(思い通りにいかなかった...)


動画のように引数をつけると、リロードしたときに関数が実行されます。さらに、左のボタンを押しても何も反応しません。

解決策

App.jsとButton.jsxの内容をそれぞれ少し変更します。

まずApp.jsのほうでは、引数にした値を別のpropsとしてコンポーネントに渡します。

App.js
- <Button func={ func2("data") }></Button>
+ <Button data="data" func={ func2 }></Button>

Button.jsxの方では、onClick内の関数の呼び出し方を以下のように変更します。

Button.jsx
- <button className="button" onClick={ props.func }>ボタンを押してね!</button>
+ <button className="button" onClick={ () => props.func(props.data) }>ボタンを押してね!</button>

できた!


無事、引数付きの関数を実行することができました!

ではまた。

Discussion

Honey32Honey32

失礼します。

確かにその方法で表面的には解決はしますが、「JavaScript の関数がどのようなものか」の基礎的な理解に進むほうが意味があると思うので、情報共有させていただきます。

引数が空か、引数があるのかの違いは、関係ありません。

func1 という式は、 「func1 関数そのもの(まだ実行しない)」を表していますが、func1() と書くと、「関数を実行して、その結果を得る」という意味に変わる、ということを認識する必要があります。

- <Button func={ func2("data") }></Button>
+ <Button func={ () => func2("data") }></Button>

なので、以上のように書き換えるだけで十分です。「func の型を変更する」のは弥縫策になってしまいます。

詳しい説明は、公式ドキュメントの以下のページにあります。

https://ja.react.dev/learn/responding-to-events

ちなみに、関数のこのような取り扱いかたは、React に限定されたものではありません。JavaScript やその他のプログラミング言語一般で「第一級関数」と呼ばれるものに関連しています。

https://developer.mozilla.org/ja/docs/Glossary/First-class_Function

n-kokin-koki

コメントありがとうございます。
記事を書いた時点では、「動くけど、なぜかは良く分からない」状態でしたので、とても参考になりました!
送っていただいたドキュメント等を参考に、さらに理解を深めたいと思います。
ありがとうございます!