1
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 関数コンポーネント間での props の受け渡し

Posted at

初めに

関数コンポーネント間での props の流れを理解するために、サンプルコードや図を入れて自分なりに整理してみました。

1. コンポーネントに変数を渡す

変数 morninghelloeveningBasicTabs コンポーネントに渡します。

App.js
const morning =  <p>Good Morning!</p>;
const hello =  <p>Hello!</p>;
const evening =  <p>Good Evening!</p>;

const App = () => {
  return (
    <div className="App">
      {/* 変数 morning、hello、evening を BasicTabs コンポーネントに渡す */}
      <BasicTabs morning={morning} hello={hello} evening={evening} />
    </div>
  );
}

export default App;
TabSample.js
const BasicTabs = props => {
  // 親コンポーネントである App コンポーネントから props を受け取る
  const { morning, hello, evening } = props;

  return (
    <Box sx={{ width: '100%' }}>
      <TabPanel value={value} index={0}>
        {morning}
      </TabPanel>
      <TabPanel value={value} index={1}>
        {hello}
      </TabPanel>
      <TabPanel value={value} index={2}>
        {evening}
      </TabPanel>
    </Box>
  );
}

image.png

完全なコードはこちらです。

2. コンポーネントにコンポーネントを渡す

関数コンポーネント MorningHelloEveningBasicTabs コンポーネントに渡します。

App.js
const Morning = () => <p>Good Morning!</p>;
const Hello = () => <p>Hello!</p>;
const Evening = () => <p>Good Evening!</p>;

const App = () => {
  return (
    <div className="App">
      {/* 関数コンポーネント Morning、Hello、Evening を BasicTabs コンポーネントに渡す */}
      <BasicTabs Morning={Morning} Hello={Hello} Evening={Evening} />
    </div>
  );
}

export default App;
TabSample.js
const BasicTabs = props => {
  const { Morning, Hello, Evening } = props;

  return (
    <Box sx={{ width: '100%' }}>
      <TabPanel value={value} index={0}>
        <Morning />
      </TabPanel>
      <TabPanel value={value} index={1}>
        <Hello />
      </TabPanel>
      <TabPanel value={value} index={2}>
        <Evening />
      </TabPanel>
    </Box>
  );
}

image.png

完全なコードはこちらです。

3. コンポーネントに state を持つコンポーネントを渡す

Button 要素を追加し、クリックするとカウントアップするような state をそれぞれ Morning コンポーネント、Hello コンポーネント、Evening コンポーネントに追加しました。

App.js
const Morning = () => {
  // カウントアップ用の state を定義
  const [count, setCount] = useState(0);
  return (
    <>
      <p>Good Morning! {count}</p>
      {/* ボタンをクリックすると、count を count + 1 で更新する */}
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}
  return (
    <>
      <p>Good Morning! {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

const Hello = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <p>Hello! {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

const Evening = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <p>Good Evening! {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

const App = () => {
  return (
    <div className="App">
      <BasicTabs Morning={Morning} Hello={Hello} Evening={Evening} />
    </div>
  );
}

export default App;

TabSample.js に変更はありません。

image.png

完全なコードはこちらです。

4. コンポーネントの共通部分を別のコンポーネントで定義する

MorningHelloEvening コンポーネントには共通化できる部分があります。それを別コンポーネントとして定義します。

App.js
const Morning = () => <Greeting greeting={"Good Morning!"}/>;
const Hello = () => <Greeting greeting={"Hello!"}/>;
const Evening = () => <Greeting greeting={"Good Evening!"}/>;

const Greeting = props => {
  const { greeting } = props;
  const [count, setCount] = useState(0);
  return (
    <>
      {/* 挨拶要素とボタン要素を共通化 */}
      <p>{greeting} {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

const App = () => {
  return (
    <div className="App">
      <Grid container>
        <Grid item xs={6}>
          <BasicTabs Morning={Morning} Hello={Hello} Evening={Evening} />
        </Grid>
      </Grid>
    </div>
  );
}

export default App;

image.png

完全なコードはこちらです。

5. state の移動

前章ではタブを切り替えるとカウントが 0 にリセットされてしまいます。これはタブ切り替え時に MorningHelloEvening コンポーネントが初期化されるためです。タブを切り替えてもカウントを保持したい場合は、親コンポーネントである BasicTabs でそれぞれのカウントを定義します。子コンポーネントに state を渡し、その子コンポーネントで state の更新を行い、その更新を親コンポーネントに反映させる場合、更新用関数も渡します。

TabSample.js
const BasicTabs = () => {
  // ここで count を定義する
  const [morningCount, setMorningCount] = useState(0);
  const [helloCount, setHelloCount] = useState(0);
  const [eveningCount, setEveningCount] = useState(0);

  return (
    <Box sx={{ width: '100%' }}>
      <TabPanel value={value} index={0}>
        {/* count を渡す */}
        <Morning count={morningCount} setCount={setMorningCount}/>
      </TabPanel>
      <TabPanel value={value} index={1}>
        <Hello count={helloCount} setCount={setHelloCount}/>
      </TabPanel>
      <TabPanel value={value} index={2}>
        <Evening count={eveningCount} setCount={setEveningCount}/>
      </TabPanel>
    </Box>
  );
}

上記のように定義した state を MorningHelloEvening コンポーネントに props として渡し、以下のように受け取ります。

TabSample.js
const Morning = props => {
  // 親コンポーネントである BasicTabs コンポーネントから props を受け取る
  const { count, setCount } = props;
  return (
    <>
      <p>Good Morning! {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

const Hello = props => {
  const { count, setCount } = props;
  return (
    <>
      <p>Hello! {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

const Evening = props => {
  const { count, setCount } = props;
  return (
    <>
      <p>Good Evening! {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

image.png

完全なコードはこちらです。

6. コンポーネントの共通部分を別のコンポーネントで定義する(再)

4. コンポーネントの共通部分を別のコンポーネントで定義する で行った共通化を再び行います。MorningHelloEvening コンポーネントで共通している state と state 更新関数、後は挨拶言葉を props として受け取るようにします。

TabSample.js
const Greeting = props => {
  const { greeting, count, setCount } = props;
  return (
    <>
      <p>{greeting} {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

これを利用すれば、MorningHelloEvening コンポーネントはそれぞれ以下のように簡潔に書くことができます。

TabSample.js
const Morning = props => <Greeting greeting="Good Morning!" {...props} />;
const Hello = props => <Greeting greeting="Hello!" {...props} />;
const Evening = props => <Greeting greeting="Good Evening!" {...props} />;

{...props} は、MorningHelloEvening コンポーネントが親コンポーネントから受け取っている props (カウント用の state、カウント更新用関数)をそのまま子コンポーネントに渡しています。省略せずに書けば、以下のようになります。

const Morning = props => <Greeting greeting="Good Morning!" count={props.count} setCount={props.setCount} />;
const Hello = props => <Greeting greeting="Hello!" count={props.count} setCount={props.setCount} />;
const Evening = props => <Greeting greeting="Good Evening!" count={props.count} setCount={props.setCount} />;

image.png

完全なコードはこちらです。

7. もっと簡単にしたい

そもそも MorningHelloEvening コンポーネントを定義する必要はありませんでした。

TabSample.js
const Greeting = props => {
  const { greeting, count, setCount } = props;
  return (
    <>
      <p>{greeting} {count}</p>
      <Button variant="contained" onClick={() => setCount(count + 1)}>Click</Button>
    </>
  );
}

const BasicTabs = () => {
  const [morningCount, setMorningCount] = useState(0);
  const [helloCount, setHelloCount] = useState(0);
  const [eveningCount, setEveningCount] = useState(0);

  return (
    <Box sx={{ width: '100%' }}>
      <TabPanel value={value} index={0}>
        {/* 共通化コンポーネントをここに直接書く */}
        <Greeting greeting="Good Morning!" count={morningCount} setCount={setMorningCount}/>
      </TabPanel>
      <TabPanel value={value} index={1}>
        <Greeting greeting="Hello!" count={helloCount} setCount={setHelloCount}/>
      </TabPanel>
      <TabPanel value={value} index={2}>
        <Greeting greeting="Good Evening!" count={eveningCount} setCount={setEveningCount}/>
      </TabPanel>
    </Box>
  );
}

image.png

完全なコードはこちらです。

8. state の移動(再)

今度は App コンポーネントまで state を移動させます。

App.js
const App = () => {
  // ここでカウント用の state を定義
  const [morningCount, setMorningCount] = useState(0);
  const [helloCount, setHelloCount] = useState(0);
  const [eveningCount, setEveningCount] = useState(0);

  return (
    <div className="App">
      <Grid container spacing={2}>
        <Grid item xs={6}>
          <BasicTabs
            morningCount={morningCount}
            setMorningCount={setMorningCount}
            helloCount={helloCount}
            setHelloCount={setHelloCount}
            eveningCount={eveningCount}
            setEveningCount={setEveningCount}
          />
        </Grid>
      </Grid>
    </div>
  );
}
TabSample.js
const BasicTabs = props => {
  const {
    morningCount, setMorningCount,
    helloCount, setHelloCount,
    eveningCount, setEveningCount,
  } = props;

  return (
    <Box sx={{ width: '100%' }}>
      <TabPanel value={value} index={0}>
        <Greeting greeting="Good Morning!" count={morningCount} setCount={setMorningCount}/>
      </TabPanel>
      <TabPanel value={value} index={1}>
        <Greeting greeting="Hello!" count={helloCount} setCount={setHelloCount}/>
      </TabPanel>
      <TabPanel value={value} index={2}>
        <Greeting greeting="Good Evening!" count={eveningCount} setCount={setEveningCount}/>
      </TabPanel>
    </Box>
  );
}

image.png

完全なコードはこちらです。

9. App コンポーネントに別の子コンポーネントを追加する

8. state の移動(再)で App コンポーネントにカウント用 state を移動したので、App コンポーネントの子コンポーネントでカウント用 state を props として渡すことができます。ここでは各カウントのサマリーを表示する子コンポーネントを作りました。。

App.js
const App = () => {
  const [morningCount, setMorningCount] = useState(0);
  const [helloCount, setHelloCount] = useState(0);
  const [eveningCount, setEveningCount] = useState(0);

  return (
    <div className="App">
      <Grid container >
        <Grid item xs={6}>
          <BasicTabs
            morningCount={morningCount}
            setMorningCount={setMorningCount}
            helloCount={helloCount}
            setHelloCount={setHelloCount}
            eveningCount={eveningCount}
            setEveningCount={setEveningCount}
          />
        </Grid>
        <Grid item xs={6}>
          <Summmary
            morningCount={morningCount}
            helloCount={helloCount}
            eveningCount={eveningCount}
          />
        </Grid>
      </Grid>
    </div>
  );
}
Summary.js
const Summary = props => {
  const { morningCount, helloCount, eveningCount } = props;
  return (
    <>
      <Typography variant="h5">Greeting count</Typography>
      <Grid container spacing={2}>
        <Grid item xs={4}>Morning Count</Grid>
        <Grid item xs={4}>Hello Count</Grid>
        <Grid item xs={4}>Evening Count</Grid>
        <Grid item xs={4}>{morningCount}</Grid>
        <Grid item xs={4}>{helloCount}</Grid>
        <Grid item xs={4}>{eveningCount}</Grid>
      </Grid>
    </>
  );
}

image.png

React-App-Google-Chrome-2022-06-18-19-33-18.gif

参考記事

1
1
0

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
1
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?