yoshikazu0110
@yoshikazu0110 (h y)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

React tyepscript 子コンポーネントで親コンポーネントのStateを更新させる

やりたいこと

React Typescriptで
子コンポーネントに親コンポーネントに定義したメソッドを渡して
子コンポーネントのセレクターの変更イベントに設定
最終的に親コンポーネントのStateを子コンポーネントのイベントで間接的に更新

現状

以下のエラーが出ているがどう修正したらいいのかよくわからない
Type 'void' is not assignable to type '(...args: any[]) => any'.

ソースはこんな感じ

親コンポネントの定義

import React,{ useState, useEffect, createRef } from 'react';
import './App.css';
import Select from './Components/Fields/Select'

function App() {
  var [registUsers, setRegistUser] = useState([""]);
  
  function test(...args: any[]): void {
    alert("test");
  }

  return (
    <div className="App">
      ↓ 子コンポーネント、以下の記述でこんな感じのエラーがでる。
      ↓ Type 'void' is not assignable to type '(...args: any[]) => any'.
      <Select onChange={test(["test1","test2"])} id="delete-user" className='delete-user' title='削除ユーザー' selectItems={registUsers}/>
    </div>
  );
}

export default App;

子コンポーネントの定義

import * as React from 'react';
import Box from '@mui/material/Box';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select, { SelectChangeEvent } from '@mui/material/Select';

type PropsType = {
  title: string
  selectItems: string[]
  className: string
  id: string
  onChange: (...args: any[]) => any;
}

export default function BasicSelect({title,selectItems,className,id,onChange}: PropsType) {
  return (
    <Box >
      <FormControl sx={{ width: '100%' }}>
        <InputLabel id="demo-simple-select-label">{title}</InputLabel>
        <Select
          labelId="user-label"
          id={id}
          label="Age"
          onChange={onChange}
          className={className}
        >
          {selectItems.map((item,index) => (
            <MenuItem value={index}>{item}</MenuItem>
          ))}
        </Select>
      </FormControl>
    </Box>
  );
}
0

1Answer

修正して再投稿します.

子コンポーネント
<FormControl sx={{ width: '100%' }}>
        <InputLabel id="demo-simple-select-label">{title}</InputLabel>
        <Select
          labelId="user-label"
          id={id}
          label="Age"
          onChange={onChange}
          className={className}
        >

子コンポーネントで受け取ったonChangeをSelectに渡していますが,イベントのコールバックはその情報を受け取るために型が定義されています.

onChange: (event: SelectChangeEvent<T>, child?: object) => void

なのでまず親・子コンポーネントともonChangeの型をこれに合わせなければなりません.

もう一点ですが

<Select onChange={test(["test1","test2"])}/>

これは関数の呼び出しであって関数オブジェクトを渡す指定ではありません.
HTMLのonchangeはイベント発生時に発火しますが,ReactのonChangeの内容は即時発火して関数オブジェクトを返さなければなりません.
任意の引数を渡すには,渡したい内容によって関数の内容を変える必要があります.

関係ないこと

今回子コンポーネントをdefault exportしているせいで,親コンポーネントのSelectとMUIのSelectが紛らわしいです.
カスタムコンポーネントの名前は明確に区別できるものを使用するべきです.

よほどのこと(具体的にはNext.jsのページ等)がない限り,コンポーネントのdefault exportは不要です.
どうしても名前が衝突する場合はasが使えますから,コンポーネントは普通にexportしましょう.

2Like

Comments

  1. @yoshikazu0110

    Questioner

    丁寧に回答していただきありがとうございます。
    子コンポーネントに関数オブジェクト渡すことできるようになりました!
    コンポーネントも紛らわしい名前にしないよいうに注意します!
    まだ自分の書いている記法などの意味を把握できてない状態なので少しずつ理解していきます!

Your answer might help someone💌