前提・実現したいこと
インプット要素を持つ 大量のリストがあり、こちらの入力を行うと入力をしたインプット要素だけでなく、他の入力を行っていないインプット要素も再レンダリングをされてしまう状態です。
こちらをどうにか入力を行ったインプット要素だけを再レンダリングさせるようにできないかな?と考えているのですが、いい方法はないでしょうか?
なお、親のコンポーネントのインプット要素を入力を行った時の再レンダリング対策はReact.memoやuseCallbackで対応済みです。
参考画像
参考MOVIE
https://gyazo.com/a8ba2cd0e58e98c305f0fcb76d5a2472
該当のソースコード
TypeScript
1// Page.tsx 2import React, { useCallback, useEffect, useState } from 'react'; 3 4import { Users } from '@/components/organisms/Users'; 5 6import { PageLayout } from '../templates'; 7 8type User = { 9 id: number; 10 name: string; 11 inputName: string; 12}; 13 14const Page: React.FC = () => { 15 const sampleUsers = [...Array(100)].map((index) => ({ 16 id: index + 1, 17 name: `name${index + 1}`, 18 inputName: '', 19 })); 20 21 const [input, setInput] = useState<string>(''); 22 const [users, setUsers] = useState<User[]>([]); 23 24 const handleInput = useCallback( 25 (newInput: string, index: number) => { 26 const copyusers = [...users]; 27 copyusers[index].inputName = newInput; 28 setUsers(copyusers); 29 }, 30 [users] 31 ); 32 33 useEffect(() => { 34 setUsers(sampleUsers); 35 }, []); 36 37 return ( 38 <PageLayout> 39 親のインプット 40 <input 41 type="text" 42 style={{ 43 border: '1px solid black', 44 }} 45 value={input} 46 onChange={(e) => setInput(e.target.value)} 47 /> 48 <Users {...{ users, handleInput }} /> 49 </PageLayout> 50 ); 51}; 52 53export default Page; 54 55
TypeScript
1// Users.tsx 2import React from 'react'; 3 4import { User } from '@/components/organisms/User'; 5 6type User = { 7 id: number; 8 name: string; 9 inputName: string; 10}; 11 12type UsersProps = { 13 users: User[]; 14 handleInput: (newInput: string, index: number) => void; 15}; 16 17export const Users: React.FC<UsersProps> = React.memo( 18 ({ users, handleInput }): JSX.Element => { 19 console.log('ここはUsersです'); 20 return ( 21 <ul style={{ marginTop: '100px' }}> 22 {users.map((user, index) => { 23 return <User key={index} {...{ index, handleInput, user }} />; 24 })} 25 </ul> 26 ); 27 } 28); 29 30Users.displayName = 'UsersComponent'; 31
TypeScript
1// User.tsx 2import React from 'react'; 3 4type User = { 5 id: number; 6 name: string; 7 inputName: string; 8}; 9 10type Props = { 11 user: User; 12 index: number; 13 handleInput: (newInput: string, index: number) => void; 14}; 15export const User: React.FC<Props> = React.memo( 16 ({ user, index, handleInput }): JSX.Element => { 17 console.log('ここはuserのindexは', index); 18 19 return ( 20 <li key={user.id}> 21 Userコンポーネント 22 <input 23 style={{ 24 margin: '10px', 25 border: '1px solid black', 26 }} 27 type="text" 28 onChange={(e) => { 29 handleInput(e.target.value, index); 30 }} 31 value={user.inputName} 32 /> 33 inputName:{user.inputName} 34 </li> 35 ); 36 }, 37 (prevProps: Props, nextProps: Props) => { 38 const prevInputName = prevProps.user; 39 const nextInputName = nextProps.user; 40 // ここで前の状態で比較をしても変わっていない状態になってしまう。。 41 return prevInputName === nextInputName; 42 } 43); 44 45User.displayName = 'UserComponent'; 46
試したこと
User.tsxの中にinput要素があり、ここでReact.memoの第二引数を使って前のPropsの状態と今のPropsの状態を比較できると調べて、それを実施してみたが、うまく動作をしなくなってしまう状態です(こちらの第二引数をなくせば動きます)
補足情報(FW/ツールのバージョンなど)
"react": "^17.0.1"
"typescript": "^4.0.3"

バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/03/02 00:27
2022/03/02 01:05
2022/03/02 01:12
2022/03/02 04:16
2022/03/02 04:46 編集
2022/03/02 05:11
2022/03/02 07:10
2022/03/02 08:03 編集
2022/03/02 08:05
2022/03/02 11:44 編集
2022/03/02 12:34