🦄

React.jsの謎仕様

2023/09/24に公開2

親コンポーネントが子コンポーネントから値を受け取る際、
関数コンポーネントであれば

const Parent: React.FC<{}> = () => {
  const [text, setText] = useState("");
  // ↑親コンポーネントで使う:textの初期値とtextを更新する関数を宣言
  // ↓子コンポーネントから受け取った値で親コンポーネントのtextを更新する関数
  const handleValueChange = (newValue: string) => {
    setText(newValue);
  };
  return (
    <div>
      <Child count={1000} handleValueChange={handleValueChange} />
      <Child2 text={text} />
    </div>
  );
}
type ChildProps2 = {
  text: string;
}
const Child2: React.FC<ChildProps2> = props => {   // 引数でpropsを受け取る
  return (
    <>
      <p className='text'>{props.text}</p>
    </>
  )
}
type ChildProps = {
  count: number;
  handleValueChange: (val: any) => void
}
const Child: React.FC<ChildProps> = props => {   // 引数でpropsを受け取る
  const handleInputChange = (event: any) => {
    const value = event.target.value;
    props.handleValueChange(value);
  }
  return (
    <>
      <input type="text" onChange={handleInputChange} />
      <p>{props.count}</p>
    </>
  )
}

と記述することで、子コンポーネントにある関数を上書きしたり、子コンポーネントのpropsの値を更新することができる。

しかし、クラスコンポーネントにリファクタリングした場合

type Parent2State={
  text:string;
}
//こっちはダメ?
class Parent2 extends React.Component<{}, Parent2State>{
constructor(props:{}){
  super(props);
  this.state={text:""};
}
  handleValueChange(newValue: string){
    this.setState({text:newValue});
  };
  render() {
    return (
      <div>
        <Child count={1000} handleValueChange={this.handleValueChange} />
        <Child2 text={this.state.text} />
      </div>
    );
  }
}
//子コンポーネントは以下略

とすると、エディタ上では特に問題ないが子コンポーネントでinputタグの値を変えると

TypeError: this.setState is not a function

と出てsetStateが既存関数として扱われない?と思われる。

しかし少し記述を変えて

type Parent2State={
  text:string;
}
class Parent2 extends React.Component<{}, Parent2State>{
constructor(props:{}){
  super(props);
  this.state={text:""};
}
  handleValueChange(newValue: string){
    this.setState({text:newValue});
  };
  render() {
    return (
      <div>
      {/*関数の宣言方法を変更した */}   
        <Child count={1000} handleValueChange={(e:string)=>this.handleValueChange(e)} />
        <Child2 text={this.state.text} />
      </div>
    );
  }
}

というようにhandleValueChange={(e:string)=>this.handleValueChange(e)}とすることで、実行しても特に問題なくなる。

Discussion

シバサキシバサキ

コメントありがとうございます!
bindしない場合、クラスの中ではthisの指すものが変わってしまうんですね。
リンク付きでありがとうございます