2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Reactで親コンポーネントのStateを子コンポーネントから変更する

Last updated at Posted at 2023-08-22

背景

Webアプリケーション開発中にReact+TypeScriptで下記のようなイメージのページを作りたいと思ったのですが,子コンポーネントのStateの変化(ここでは,「表示数セレクタが選択されること」)を親コンポーネントのレンダリングされる別コンポーネント(ここでは,card)の表示数に反映させる方法がわからず,調査したので,メモとして残します.

image.png

(補足)今回やろうとしていることは,上記のイメージ図にあるように,子コンポーネントである表示数変更用のセレクタの変更をindexページ(親コンポーネント)に渡し,変更されたStateに応じて同じく子コンポーネントのcardコンポーネントの表示数をコントロールする実装です.

環境

TypeScript 4.9.4
React 18.2.0
(なお,webアプリケーションフレームワークには Ruby on Rails を使用しています)

実装

ポイントはpropsにState更新用のメソッド(setValue)を設定して,親コンポーネントから更新したいState(count)を更新するメソッド(setCount)を渡してあげることです.

  • 子コンポーネント
    BasicSelect.tsx
    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 Props = {
      value: number|string, // state
      setValue // callback (stateを変更するためのprops)
      options: Array<number | string>
    };
    
    export const BasicSelect = ({value, options, setValue}: Props) => {
      const handleChange = (event: SelectChangeEvent) => {
        setValue(event.target.value);  //親コンポーネントへのstateの引き渡し
      };
    
      return (
        <Box>
          <FormControl variant="filled" sx={{ m: 1, minWidth: 150 }}>
            <InputLabel id="select-label">表示数</InputLabel>
            <Select
              labelId="select-label"
              id="select"
              value={value}
              label="count"
              onChange={handleChange}
            >
              {options.map((option) => <MenuItem key={option} value={option}>{option}</MenuItem>)}  
            </Select>
          </FormControl>
        </Box>
      );
    }
    
    
  • 親コンポーネント
    ここでのカードの実装やindexページの実装もMaterial UIを頼らせていただきました.
    いくつか割愛している箇所もあるので,気になる方は下記のドキュメントをご覧ください.
    React Grid component - Material UI
    React Card component - Material UI
    index.tsx
    import { MyCard } from 'app/javascript/components/MyCard/MyCard'; //表示するカードコンポーネント(ここの実装は割愛します.詳細は参考文献をご覧ください)
    import { BasicSelect } from 'app/javascript/components/BasicSelect/BasicSelect'; //子コンポーネントのインポート
    import { Grid,  Box} from '@mui/material';
    import React from 'react';
    import ReactDOM from 'react-dom';
    
    export const Index = () => {
      const display_count_options = [1, 2, 3, 4]; //selector options
      const [count, setCount] = React.useState(2); //state変数,初期値と更新のための関数を宣言
      const { card_data } = getCardData(); //表示するCardに記載する内容を配列で取得(ここの実装は割愛します.詳細は参考文献をご覧ください)
      
      return (
        <>
          <BasicSelect value={count} setValue={setCount} options={display_count_options} /> 
          <br/>
          <Box sx={{ flexGrow: 1 }}>
            <Grid container spacing={2}>
              {card_data.slice(0,count).map((data) =>
                <Grid item xs={4} sx={{ padding: 0 }} key={data.name}>
                  <MyCard/>          
                </Grid>
              )}  
            </Grid>
          </Box>
        </>
      );
    };
    
    ReactDOM.render(<Index />, document.getElementById('Index'));
    
    

結果

思惑通り,セレクタの選択内容に応じてカードの表示数を変更できるようになりました.
画面収録-2023-08-22-14.14.35.gif

参考文献

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?