質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
React Native

React Nativeは、ネイティブモバイルアプリ(iOS/Android)を作成できるJavaScriptフレームワークです。Reactと同じ設計のため、宣言的なコンポーネントでリッチなUIを開発することが可能です。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

761閲覧

配列[]の要素数ではなく、各要素の値でstateの管理をする方法

tomaa

総合スコア84

React Native

React Nativeは、ネイティブモバイルアプリ(iOS/Android)を作成できるJavaScriptフレームワークです。Reactと同じ設計のため、宣言的なコンポーネントでリッチなUIを開発することが可能です。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2020/08/10 11:39

前提・実現したいこと

React Nativeを利用してアプリの開発をしています。


下記の3つの要素が1組となるコンポーネントがあります。

  • TextInput
  • Button(追加)
  • Button(削除)

追加ボタンを押すと、コンポーネントが追加され、削除を押すと削除されます。

イメージ説明


追加や削除されるコンポーネントは、配列で管理され、それぞれ入力されたテキストの値は配列の値として管理されます。

削除ボタンが押されると、対象のコンポーネントが削除され、そのコンポーネントは、

  1. 画面に表示されなくなる
  2. 配列から要素が削除される
  3. テキストインプットの枠にはコンポーネントの順番と、配列のindexの順番が一致した値が表示される

という動きになってほしいのですが、3番目の動作がうまくいきません。


例えば、下記のように

イメージ説明

  • 0番目に→000を入力
  • 1番目に→111を入力
  • 2番目に→222を入力

した状態で1番目の削除ボタンを押すと、

下記のように

イメージ説明

0番目に→000が表示(OK)
1番目に→111が表示(222と表示したい)

となってしまいます。

発生している問題

削除ボタンを押した際に、実際の配列は、左上の確認[]に表示しているように、要素は正しい値を持っていますが、レンダーされる画面は正しい値が表示されません。

予想している原因は、stateで管理している配列が、要素数の変化で状態変化を制御しており、要素自体の変化に対応していない事だと思っています。

下記のコードはイメージですが、このようにuseEffectを利用する事が、対策になるかと考えていますが、実際の実装の方法がわかりません。

そこで、下記のコードのような場合、配列の要素の変化ごとにstateを利用して再レンダーさせる方法を知りたいです。

方法等について、ご存知の方おりましたら、ご教授いただけないでしょうか?

該当のソースコード

JS

1import React, { useState, useEffect } from "react"; 2import { View, Text, Button, TextInput, StyleSheet } from "react-native"; 3 4function Item({ handleInput, handleAdd, handleDelete, index }) { 5 return ( 6 <View style={styles.list}> 7 <Text>{index}</Text> 8 <TextInput 9 style={{ borderWidth: 1 }} 10 onChange={(e) => { 11 handleInput(index, e.nativeEvent.text); 12 console.log(number); //配列の値確認 13 }} 14 ></TextInput> 15 <Button 16 title="追加" 17 onPress={() => { 18 handleAdd(); 19 }} 20 /> 21 <Button 22 title="削除" 23 onPress={() => { 24 handleDelete(index); 25 }} 26 /> 27 </View> 28 ); 29} 30 31export default function TestStateArray() { 32 const [count, setCount] = useState(1); 33 const [number, setNumber] = useState([]); 34 35 // useEffect(() => { 36 // setNumber(number); 37 // }, [number][i]); 38 39 function handleAdd() { 40 setCount((v) => v + 1); 41 } 42 43 function handleDelete(index) { 44 setCount((v) => v - 1); 45 setNumber((v) => { 46 v.splice(index, 1); 47 return v; 48 }); 49 } 50 51 function handleInput(index, text) { 52 setNumber((v) => { 53 v[index] = text; 54 console.log(number); 55 return v; 56 }); 57 } 58 59 return ( 60 <View> 61 <Text>確認{JSON.stringify(number)}</Text> 62 63 {Array.from({ length: count }, (_, i) => ( 64 <Item 65 number={number} 66 handleInput={handleInput} 67 handleAdd={handleAdd} 68 handleDelete={handleDelete} 69 key={i} 70 index={i} 71 /> 72 ))} 73 </View> 74 ); 75} 76 77const styles = StyleSheet.create({ 78 list: { 79 margin: 10, 80 padding: 10, 81 backgroundColor: "#ddd", 82 }, 83}); 84

補足情報(FW/ツールのバージョンなど)

node : 12.18.3
react native : 4.10.1
expo : 3.22.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

<item>の生成の際に、keyへ配列のインデックスであるiを指定してしまっているのが要因です。

keyは、Reactコンポーネントの再構築の際に、「同じキーなら同じオブジェクト」として描画を省略するために使うものなので、配列のインデックスをキーにしてしまうと、今回のような配列を一部削除した場合に、違うオブジェクトが転用される結果となってしまいます。

中身のnumberも含めて、i + '-' + number のようなものをキーとするのが適切です。

投稿2020/08/10 12:58

maisumakun

総合スコア145186

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tomaa

2020/08/10 14:12

ご回答いただきありがとうございます。 非常にわかりずらく、細かな問題をアドバイスしていただき参考になりました。 大変助かりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問