Coding 공부/React

[React] 컴포넌트 key, Props와 State, 조건부 렌더링 7가지 방법, Person 추가 및 삭제 및 수정 코드

CBJH 2024. 5. 27.
728x90
반응형

1. 컴포넌트 key 설정

Warning: Each child in a list should have a unique "key" prop.

컴포넌트마다 고유한 키를 설정해줘야한다. 무시해도되는 오류지만 이후 코드가 복잡해질 경우 고려해야될 사항이다.

render(){
    const result = this.state.personList.map(
      (data)=>(<Person  key={data.id}
                        id={data.id}
                        name={data.name}
                        age={data.age}
                        height={data.height}/>)
    )
    return(
      <div id='app'>
        <InputComp/>
        {result}
      </div>
    )
  }
  • Person 컴포넌트에 key 키워드를 추가해주면 해결된다.(컴포넌트를 구분해주는 역할로 사용 됨)

 

 

2. Props, State 예제코드

 

2.1 주요 개념 정리

  1. Props(속성): 부모 컴포넌트가 자식 컴포넌트에 데이터를 전달하는 방법.
  2. State(상태): 컴포넌트 자체에서 관리하는 데이터.
  3. 함수 전달: 부모 컴포넌트가 자식 컴포넌트에게 함수를 props로 전달하여, 자식 컴포넌트에서 부모 컴포넌트의 상태를 변경할 수 있게 함.

2.2 코드 설명 및 주석 추가

inputComp.js

addPersonInfo = () => {
    alert('추가!');
    // 비구조화 할당을 통해 this.state에서 id, name, age, height를 추출
    const { id, name, age, height } = this.state;
    // 추출한 값들로 새로운 person 객체 생성
    const personObj = { id: id, name: name, age: age, height: height };
    // props로 전달된 addPersonInfo 함수를 호출하여 생성된 person 객체를 부모 컴포넌트(App)로 전달
    this.props.addPersonInfo(personObj);
}

 

App.js

import { Component } from 'react';
import './App.css';
import Person from './components/Person.js';
import InputComp from './components/inputComp.js';

class App extends Component {
  constructor(props) {
    super(props);
    // 상태 초기화: personList 배열에 초기 데이터 설정
    this.state = {
      personList: [
        { id: 1, name: '이민호', age: 20, height: 180 },
        { id: 2, name: '정채연', age: 21, height: 170 },
        { id: 3, name: '송중기', age: 22, height: 176 }
      ]
    };
  }

  // 새로운 person 객체를 추가하는 함수
  // obj는 InputComp.js의 addPerson에서 props로 받은 personObj이다.
  addPersonInfo = (obj) => {
    alert('추가!(App)');
    console.log(obj);
    // 기존 personList에 새로운 객체를 추가한 배열을 생성(concat 함수)
    const concatedList = this.state.personList.concat(obj);
    // 새로운 배열로 상태 업데이트
    this.setState({
      personList: concatedList
    }); // setState가 호출되면 render 메서드가 다시 호출됨
  }

  render() {
    // personList를 순회하며 Person 컴포넌트를 생성
    const result = this.state.personList.map(
      (data) => (
        <Person
          key={data.id}
          id={data.id}
          name={data.name}
          age={data.age}
          height={data.height}
        />
      )
    );
    return (
      <div id='app'>
        {/* InputComp에 addPersonInfo 함수를 props로 전달 */}
        <InputComp addPersonInfo={this.addPersonInfo} />
        {result}
      </div>
    );
  }
}

export default App;

2.3 설명

  1. App 컴포넌트에서 함수 전달하기
<InputComp addPersonInfo={this.addPersonInfo} />
  1. InputComp 컴포넌트를 렌더링할 때, addPersonInfo 함수를 props로 전달합니다.
  2. InputComp에서 함수 사용하기
this.props.addPersonInfo(personObj);
  1. InputComp는 this.props.addPersonInfo를 호출하여 부모(App) 컴포넌트에 새로운 person 객체를 전달합니다.
  2. 함수명 동일성 여부
  3. 함수명을 동일하게 할 필요는 없습니다. 중요한 것은 함수가 props로 전달되었고, 자식 컴포넌트에서 그 함수가 호출된다는 것입니다. 함수명은 다르게 지어도 문제없습니다.

2.4 요약

  • 부모 컴포넌트(App)가 자식 컴포넌트(InputComp)에게 함수를 props로 전달합니다.
  • 자식 컴포넌트(InputComp)는 이 함수를 호출하여 부모 컴포넌트의 상태를 변경할 수 있습니다.
  • 함수명은 동일할 필요가 없으며, props로 전달된 함수를 사용하기만 하면 됩니다.
  • props가 자바에도 있어서 매개변수인줄알았는데 property의 약자로, '부모에게 받아온 데이터'이다.

 

 

 

3. React 애플리케이션에서 조건부 렌더링을 구현하는 7가지 방법

 

이론 링크 : https://www.digitalocean.com/community/tutorials/7-ways-to-implement-conditional-rendering-in-react-applications

 

 

4. 코드 추가 부분

  • Person 추가, 삭제, 수정(버튼까지만) 기능 추가
  • Person.js : 삭제, 수정 버튼
  • InputComp.js : Person 추가
//App.js 코드
import {Component} from 'react';
import './App.css';
import Person from './components/Person.js'
import InputComp from './components/inputComp.js';

class App extends Component{
  constructor(props){
    super(props)
    this.state={
      personList:[{id: 1, name:'이민호', age: 20, height: 180},
                  {id: 2, name:'정채연', age: 21, height: 170},
                  {id: 3, name:'송중기', age: 22, height: 176}]

    }
  }
  // 새로운 person 객체를 추가하는 함수
  addPersonInfo = (obj) => {
    alert('추가!(App)');
    console.log(obj);
    // 기존 personList에 새로운 객체를 추가한 배열을 생성
    const concatedList = this.state.personList.concat(obj);
    // 새로운 배열로 상태 업데이트
    this.setState({
      personList: concatedList
    }); // setState가 호출되면 render 메서드가 다시 호출됨
  }
  
  // 특정 id를 가진 person 객체를 삭제하는 함수
  deletePersonInfo = (id) => {
    alert('삭제!(App)');
    alert('Person 컴포넌트에서 받은 삭제할 아이디: ' + id); // 1,2,3
    // personList 배열에서 id가 일치하지 않는 객체들만 필터링하여 새로운 배열 생성
    const filteredList = this.state.personList.filter((data) => (data.id !== id));
    // 새로운 배열로 상태 업데이트
    this.setState({
      personList: filteredList
    });
  }

  render(){
    // personList를 순회하며 Person 컴포넌트를 생성
    const result = this.state.personList.map(
      (data)=>(<Person  key={data.id}
                        id={data.id}
                        name={data.name}
                        age={data.age}
                        height={data.height}
                        deletePersonInfo={this.deletePersonInfo}/>)
    )
    return(
      <div id='app'>
        <InputComp addPersonInfo={this.addPersonInfo}/>
        {result}
      </div>
    )
  }
}

export default App;
  •  
  • 부모(App) 컴포넌트가 자식(Person) 컴포넌트에게 deletePersonInfo 함수를 props로 전달합니다.
  • 자식(Person) 컴포넌트는 이 함수를 호출하여 자신의 id를 부모에게 전달합니다.
  • 부모(App) 컴포넌트는 전달받은 id를 이용해 상태를 업데이트하고, 해당 id를 가진 객체를 personList에서 제거합니다.
//InputComp.js 코드
import { Component } from 'react';
import '../css/InputComp.css'

class InputComp extends Component{
    constructor(props){
        super(props)
        this.state={
            id:'',
            name:'',
            age:'',
            height:'',
        }
    }

    addPersonInfo = () => {
        alert('추가!');
        // 비구조화 할당을 통해 this.state에서 id, name, age, height를 추출
        const { id, name, age, height } = this.state;
        // 추출한 값들로 새로운 person 객체 생성
        const personObj = { id: id, name: name, age: age, height: height };
        // props로 전달된 addPersonInfo 함수를 호출하여 생성된 person 객체를 부모 컴포넌트(App)로 전달
        this.props.addPersonInfo(personObj);
    }
    idChange=(e)=>{
        console.log(e.target.value)
        this.setState({
            id:e.target.value
        })
    }
    nameChange=(e)=>{
        console.log(e.target.value)
        this.setState({
            name:e.target.value
        })
    }
    ageChange=(e)=>{
        console.log(e.target.value)
        this.setState({
            age:e.target.value
        })
    }
    heightChange=(e)=>{
        console.log(e.target.value)
        this.setState({
            height:e.target.value
        })
    }
    
    render(){
        return(
            <div id='input-comp'>
                <input type='text' placeholder='아이디' onChange={this.idChange}/>
                <input type='text' placeholder='이름' onChange={this.nameChange}/>
                <input type='text' placeholder='나이' onChange={this.ageChange}/>
                <input type='text' placeholder='키' onChange={this.heightChange}/>
                <button onClick={this.addPersonInfo}>추가</button>
            </div>
        )
    }
}

export default InputComp;
//Person.js 코드
import '../css/Person.css'

function Person(props){
    // 삭제 버튼 클릭 시 호출되는 함수
    const deletePersonInfo = () => {
        alert('삭제!(Person)');
        // props로 전달받은 deletePersonInfo 함수를 호출하면서 자신의 id를 인자로 전달
        props.deletePersonInfo(props.id);
    };
    const updatePersonInfo=()=>{
        alert('수정!(Person)')
    }
    return(
        <div id='person'>
            <div>
                아이디: {props.id}
            </div> 
            <div>
                이름: {props.name}
            </div> 
            <div>
                나이: {props.age}
            </div>
            <div>
                키: {props.height}
            </div>               
            <div>
                {/* 삭제 버튼에 onClick 이벤트로 deletePersonInfo 함수 연결 */}
                <button onClick={deletePersonInfo}>삭제</button>
                <button onClick={updatePersonInfo}>수정</button>
            </div>
        </div>
    )
}

export default Person;
  • 상위 컴포넌트 App.js에게 props로 deletePersonInfo를 보낸다. 매개변수엔 props.id 값을 보낸다.
/*Person.css 코드*/
#Person {
    height: 100px;
    width: 50px;
    background-color: aquamarine;
    margin: 10px;
}

#person>div {
    height: 30px;
}

#person>div:nth-child(1) {
    background-color: blueviolet;
}

#person>div:nth-child(2) {
    background-color: chartreuse;
}

#person>div:nth-child(3) {
    background-color: brown;
}

#person>div:nth-child(3) {
    background-color: lightsteelblue;
}

#person>div:nth-child(3) {
    background-color: lightpink;
}

 

4.1 deletePersonInfo 함수의 작동 설명

주요 개념

  1. 함수 전달: 부모 컴포넌트가 자식 컴포넌트에게 함수를 전달합니다.
  2. 함수 호출: 자식 컴포넌트가 전달받은 함수를 호출하여 부모 컴포넌트의 상태를 변경합니다.

코드 설명 및 주석 추가

Person.js

function Person(props) {
    // 삭제 버튼 클릭 시 호출되는 함수
    const deletePersonInfo = () => {
        alert('삭제!(Person)');
        // props로 전달받은 deletePersonInfo 함수를 호출하면서 자신의 id를 인자로 전달
        props.deletePersonInfo(props.id);
    };

    return (
        <div>
            <h2>{props.name}</h2>
            <p>Age: {props.age}</p>
            <p>Height: {props.height}</p>
            {/* 삭제 버튼에 onClick 이벤트로 deletePersonInfo 함수 연결 */}
            <button onClick={deletePersonInfo}>삭제</button>
        </div>
    );
}

export default Person;

App.js

import { Component } from 'react';
import './App.css';
import Person from './components/Person.js';
import InputComp from './components/inputComp.js';

class App extends Component {
  constructor(props) {
    super(props);
    // 초기 상태 설정: personList 배열에 초기 데이터 설정
    this.state = {
      personList: [
        { id: 1, name: '이민호', age: 20, height: 180 },
        { id: 2, name: '정채연', age: 21, height: 170 },
        { id: 3, name: '송중기', age: 22, height: 176 }
      ]
    };
  }

  // 새로운 person 객체를 추가하는 함수
  addPersonInfo = (obj) => {
    alert('추가!(App)');
    console.log(obj);
    // 기존 personList에 새로운 객체를 추가한 배열을 생성
    const concatedList = this.state.personList.concat(obj);
    // 새로운 배열로 상태 업데이트
    this.setState({
      personList: concatedList
    }); // setState가 호출되면 render 메서드가 다시 호출됨
  }

  // 특정 id를 가진 person 객체를 삭제하는 함수
  deletePersonInfo = (id) => {
    alert('삭제!(App)');
    alert('Person 컴포넌트에서 받은 삭제할 아이디: ' + id); // 1,2,3
    // personList 배열에서 id가 일치하지 않는 객체들만 필터링하여 새로운 배열 생성
    const filteredList = this.state.personList.filter((data) => (data.id !== id));
    // 새로운 배열로 상태 업데이트
    this.setState({
      personList: filteredList
    });
  }

  render() {
    // personList를 순회하며 Person 컴포넌트를 생성
    const result = this.state.personList.map(
      (data) => (
        <Person
          key={data.id}
          id={data.id}
          name={data.name}
          age={data.age}
          height={data.height}
          deletePersonInfo={this.deletePersonInfo} // deletePersonInfo 함수를 props로 전달
        />
      )
    );
    return (
      <div id='app'>
        {/* InputComp에 addPersonInfo 함수를 props로 전달 */}
        <InputComp addPersonInfo={this.addPersonInfo} />
        {result}
      </div>
    );
  }
}

export default App;

상세 설명

  1. App 컴포넌트에서 함수 전달하기
    • deletePersonInfo 함수를 Person 컴포넌트에 props로 전달합니다.
<Person
  key={data.id}
  id={data.id}
  name={data.name}
  age={data.age}
  height={data.height}
  deletePersonInfo={this.deletePersonInfo}
/>
  1. Person 컴포넌트에서 함수 사용하기
    • Person 컴포넌트는 props로 전달받은 deletePersonInfo 함수를 사용하여 자신의 id를 부모 컴포넌트에게 전달합니다.
props.deletePersonInfo(props.id);
  1. App 컴포넌트에서 상태 업데이트
    • deletePersonInfo 함수는 전달받은 id를 이용하여 personList 배열에서 해당 id를 가진 객체를 제거합니다.
const filteredList = this.state.personList.filter((data) => (data.id !== id));
this.setState({ personList: filteredList });

요약

  • 부모(App) 컴포넌트가 자식(Person) 컴포넌트에게 deletePersonInfo 함수를 props로 전달합니다.
  • 자식(Person) 컴포넌트는 이 함수를 호출하여 자신의 id를 부모에게 전달합니다.
  • 부모(App) 컴포넌트는 전달받은 id를 이용해 상태를 업데이트하고, 해당 id를 가진 객체를 personList에서 제거합니다.

댓글