본문 바로가기

Programming/국비학원

2220802 - 리액트 - (Read) 메뉴 클릭 시 내용 표시 / (Create) 생성버튼 클릭 시 목록에 추가

상위메뉴 클릭 - 하위내용 표시
  •  
  • App

import { Component } from 'react';
import './App.css';
import Subject from './Subject';
import TOC from './TOC'
import Content from './Content'

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: 브라우저에 표시

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
    } else if (this.state.mode==='read') {
      _title=this.state.contents[0].title;
      _desc=this.state.contents[0].desc;
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={()=>{  //props의 형태로 Subject에 전달되는 함수
          this.setState({mode:'welcome'});  //브라우저 첫 화면은 환영합니다 표시
        }}></Subject> 
        {/* <header> 
          <h1>
            <a href='/' onClick={function(event){
              event.preventDefault();
              this.setState({
                mode:'welcome'
              });
              }.bind(this)}>
              {this.state.subject.title}
              </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>          */}
        <TOC data={this.state.contents} 
        onChangePage={()=>{
          this.setState({mode:'read'});
          }}></TOC>   
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }
}

export default App;

 

  • Subject

import { Component } from 'react';

class Subject extends Component{
    render(){
      console.log('Subject 컴포넌트가 렌더링됨');
      return(
        <header>
          <h1>
            <a href='/' onClick={(event)=>{
              event.preventDefault();
              this.props.onChangePage();
              }}>
              {this.props.title}
            </a>
          </h1>
          <p>{this.props.sub}</p>
        </header>        
      );
    }
}

export default Subject;

 

 

  • TOC

import { Component } from 'react';

class TOC extends Component{
    render(){
      console.log('TOC 컴포넌트가 렌더링됨');
      let lists=[];
      let data=this.props.data;
      let i=0;
      while(i<data.length){
        lists.push(<li key={data[i].id}>
          <a href={"/content/"+data[i].id}  
          onClick={(event)=>{event.preventDefault(); this.props.onChangePage();}}> //클릭하면 전달된 함수 호출하도록 함
          {data[i].title}
          </a>
          </li>);
        i++;
      }

      return(
        <nav>
          <ul>
             {lists}
          </ul>
        </nav>
      );
    }
  }

export default TOC;

 

 

 

  • 기능 구현 테스트
  • App

import { Component } from 'react';
import './App.css';
import Subject from './Subject';
import TOC from './TOC'
import Content from './Content'

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      selected_content_id:2,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){  //테스트 중 - 2번째 목록 선택했을 때 2번째 데이터의 정보 불러오기
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={function(){
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }.bind(this)}></Subject> 
        <TOC data={this.state.contents} 
        onChangePage={function(){
          this.setState({mode:'read'});
          //alert('목록 선택');
          }.bind(this)}></TOC> 
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }
}

export default App;

 

 

  • 기능 구현
  • App

import { Component } from 'react';
import './App.css';
import Subject from './Subject';
import TOC from './TOC'
import Content from './Content'

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={()=>{
          this.setState({mode:'welcome'});
        }}></Subject> 
        <TOC data={this.state.contents} 
        onChangePage={(id)=>{this.setState({mode:'read',selected_content_id:Number(id)});}}></TOC> 
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }
}

export default App;

 

 

  • TOC

import { Component } from 'react';

class TOC extends Component{
    render(){
      console.log('TOC 컴포넌트가 렌더링됨');
      let lists=[];
      let data=this.props.data;
      let i=0;
      while(i<data.length){
        lists.push(<li key={data[i].id}><a 
        href={"/content/"+data[i].id} 
        data-id={data[i].id}  
        onClick={(event)=>{
            event.preventDefault(); 
            this.props.onChangePage(event.target.dataset.id);  //클릭한 앵커 태그의 데이터들 중 data-로 시작하는 속성 접근(dataset)해 접두사 뒤의 속성값(id) 가져옴 ex. data-abc면 dataset.abc
          }}>
          {data[i].title}
          </a>
          </li>);
        i++;
      }

      return(
        <nav>
          <ul>
             {lists}
          </ul>
        </nav>
      );
    }
  }

export default TOC;

 

 

 

생성 버튼 클릭 - 목록에 추가
  • 생성/수정/삭제 버튼 추가
  • App

import { Component } from 'react';
import './App.css';
import Subject from './Subject';
import TOC from './TOC'
import Content from './Content'

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={function(){
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }.bind(this)}></Subject> 
        {/* <header> 
          <h1>
            <a href='/' onClick={function(event){
              event.preventDefault();
              this.setState({
                mode:'welcome'
              });
              }.bind(this)}>
              {this.state.subject.title}
              </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>          */}
        <TOC data={this.state.contents} 
        onChangePage={function(id){
          debugger; 
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }.bind(this)}></TOC> 
        <ul>
          <li><a href='/create'>생성</a></li>
          <li><a href='/update'>수정</a></li>
          <li><input type='button' value='삭제'></input></li>
        </ul>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }
}

export default App;

 

 

=> 컴포넌트 별도 파일로 분리

  • App

import { Component } from 'react';
import './App.css';
import Subject from '../src/Components/Subject';
import TOC from '../src/Components/TOC'
import Content from '../src/Components/Content'
import Control from '../src/Components/Control'

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={function(){
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }.bind(this)}></Subject> 
        {/* <header> 
          <h1>
            <a href='/' onClick={function(event){
              event.preventDefault();
              this.setState({
                mode:'welcome'
              });
              }.bind(this)}>
              {this.state.subject.title}
              </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>          */}
        <TOC data={this.state.contents} 
        onChangePage={function(id){
          debugger; 
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }.bind(this)}></TOC> 
        <Control></Control> 
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }
}

export default App;

 

 

  • Control.js

import { Component } from 'react';

class Control extends Component{
render(){
    return(
        <ul>
          <li><a href='/create'>생성</a></li>
          <li><a href='/update'>수정</a></li>
          <li><input type='button' value='삭제'></input></li>
        </ul>
    );
}
}

export default Control;

 

 

  • 각 버튼 클릭 시 모드 변경 기능 추가
  • App

import { Component } from 'react';
import './App.css';
import Subject from '../src/Components/Subject';
import TOC from '../src/Components/TOC'
import Content from '../src/Components/Content'
import Control from '../src/Components/Control'

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={function(){
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }.bind(this)}></Subject> 
        <TOC data={this.state.contents} 
        onChangePage={function(id){
          debugger; 
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }.bind(this)}></TOC> 
        <Control onChangeMode={(_mode)=>{this.setState({  
            mode:_mode
          });}}></Control>
        <Content title={_title} desc={_desc}></Content>
      </div>
      );
  }
}

export default App;

 

 

  • 클릭 시 속성 전달
  • Control

import { Component } from 'react';

class Control extends Component{
render(){
    return(
        <ul>
          <li><a href='/create' onClick={event=>{
            event.preventDefault();
            this.props.onChangeMode('create');
          }}>생성</a></li>
          <li><a href='/update'  onClick={event=>{
            event.preventDefault();
            this.props.onChangeMode('update');
          }}>수정</a></li>
          <li><input type='button' value='삭제' onClick={event=>{
            event.preventDefault();
            this.props.onChangeMode('delete');
          }}></input></li>
        </ul>
    );
}
}

export default Control;

 

 

 

  • create 담을 변수 생성
  • App

import { Component } from 'react';
import './App.css';
import Subject from '../src/Components/Subject';
import TOC from '../src/Components/TOC'
import ReadContent from './Components/ReadContent'
import Control from '../src/Components/Control'

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc, _article=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={function(){
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }.bind(this)}></Subject> 
        {/* <header> 
          <h1>
            <a href='/' onClick={function(event){
              event.preventDefault();
              this.setState({
                mode:'welcome'
              });
              }.bind(this)}>
              {this.state.subject.title}
              </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>          */}
        <TOC data={this.state.contents} 
        onChangePage={id=>{
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }}></TOC> 
        <Control onChangeMode={_mode=>{this.setState({
            mode:_mode
          });}}></Control>
          {_article}
        {/* <ReadContent title={_title} desc={_desc}></ReadContent> */}
      </div>
      );
  }
}

export default App;

 

 

  • CreateContent

import { Component } from "react";

class CreateContent extends Component{
    render(){
        console.log('CreateContent 렌더링 됨'); //렌더링=호출되어 브라우저에 불려옴
        return(
            <article>
                <h2>생성하기</h2>
                <form action='/create_process' method="post">
                    <p>
                        <label>목차 이름</label>
                        <input type='text' name='title' placeholder="목차 이름 입력"></input>
                    </p>
                    <p>
                        <label>세부 설명</label>
                        <textarea name='desc' placeholder="세부 설명 입력"></textarea>
                    </p>
                    <p>
                        <input type='submit' value='생성'></input>
                    </p>
                </form>
            </article>
        );
    }
}

export default CreateContent;

 

 

 

  • 생성하기 누르면 CreateContent 창 표시
  • App

import { Component } from 'react';
import './App.css';
import Subject from '../src/Components/Subject';
import TOC from '../src/Components/TOC'
import ReadContent from './Components/ReadContent'
import Control from '../src/Components/Control'
import CreateContent  from '../src/Components/CreateContent';

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc, _article=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode === 'create'){  
      _article=<CreateContent></CreateContent>  
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={function(){
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }.bind(this)}></Subject> 
        {/* <header> 
          <h1>
            <a href='/' onClick={function(event){
              event.preventDefault();
              this.setState({
                mode:'welcome'
              });
              }.bind(this)}>
              {this.state.subject.title}
              </a>
          </h1>
          <p>{this.state.subject.sub}</p>
        </header>          */}
        <TOC data={this.state.contents} 
        onChangePage={id=>{
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }}></TOC> 
        <Control onChangeMode={_mode=>{this.setState({
            mode:_mode
        });}}></Control>
        {_article}  
        {/* <ReadContent title={_title} desc={_desc}></ReadContent> */}
      </div>
      );
  }
}

export default App;

 

 

 

  • 생성하기 창 속 생성 버튼 클릭 - 데이터 전달 기능 테스트
  • CreateContent

import { Component } from "react";

class CreateContent extends Component{
    render(){
        console.log('CreateContent 렌더링 됨'); //렌더링=호출되어 브라우저에 불려옴
        return(
            <article>
                <h2>생성하기</h2>
                <form action='/create_process' method="post" 
                onSubmit={(event)=>{ 
                    event.preventDefault();
                    this.props.submitValue(event.target.title.valueevent.target.desc.value);
                }}>
                    <p>
                        <label>목차 이름</label>
                        <input type='text' name='title' placeholder="목차 이름 입력"></input>
                    </p>
                    <p>
                        <label>세부 설명</label>
                        <textarea name='desc' placeholder="세부 설명 입력"></textarea>
                    </p>
                    <p>
                        <input type='submit' value='생성'></input>
                    </p>
                </form>
            </article>
        );
    }
}

export default CreateContent;

 

 

  • App

import { Component } from 'react';
import './App.css';
import Subject from '../src/Components/Subject';
import TOC from '../src/Components/TOC'
import ReadContent from './Components/ReadContent'
import Control from '../src/Components/Control'
import CreateContent  from '../src/Components/CreateContent';

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc, _article=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode === 'create'){
      _article=<CreateContent submitValue={(_title,_desc)=>//위 같은 이름 변수와 다름 //외부에서 받는 매개변수임
        console.log(_title,_desc);
      }}></CreateContent>
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={function(){
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }.bind(this)}></Subject> 
        <TOC data={this.state.contents} 
        onChangePage={id=>{
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }}></TOC> 
        <Control onChangeMode={_mode=>{this.setState({
            mode:_mode
        });}}></Control>
        {_article}
        {/* <ReadContent title={_title} desc={_desc}></ReadContent> */}
      </div>
      );
  }
}

export default App;

 

 

 

  • 생성 버튼 클릭 - 목록 추가 기능 구현 (state.contents.id 이용)
  • App (1. push 사용)

import { Component } from 'react';
import './App.css';
import Subject from '../src/Components/Subject';
import TOC from '../src/Components/TOC'
import ReadContent from './Components/ReadContent'
import Control from '../src/Components/Control'
import CreateContent  from '../src/Components/CreateContent';

class App extends Component{
  constructor(props){
    super(props);
    this.max_content_id=3;
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc, _article=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode === 'create'){
      _article=<CreateContent submitValue={(_title,_desc)=>{ 
        this.max_content_id=this.max_content_id+1;  
        this.state.contents.push({   
          id:this.max_content_id+1,
          title:_title,
          desc:_desc
        });
        this.setState({ //setState 호출해야 바뀐 state 다시 렌더링함
          contents:this.state.contents 
        });
      }}></CreateContent>
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={()=>{
          this.setState({mode:'welcome'});
        }}></Subject> 
        <TOC data={this.state.contents} 
        onChangePage={id=>{
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }}></TOC> 
        <Control onChangeMode={_mode=>{this.setState({
            mode:_mode
        });}}></Control>
        {_article}
      </div>
      );
  }
}

export default App;

 

 

※ 리액트 성능 개선 => push 보다 concat

 

 

  • 2. concat 사용

import { Component } from 'react';
import './App.css';
import Subject from '../src/Components/Subject';
import TOC from '../src/Components/TOC'
import ReadContent from './Components/ReadContent'
import Control from '../src/Components/Control'
import CreateContent  from '../src/Components/CreateContent';

class App extends Component{
  constructor(props){
    super(props);
    this.max_content_id=3;
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc, _article=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode === 'create'){
      _article=<CreateContent submitValue={(_title,_desc)=>{ //위 같은 이름 변수와 다름 //외부에서 받는 매개변수임
        this.max_content_id=this.max_content_id+1;
        // this.state.contents.push({
        //   id:this.max_content_id+1,
        //   title:_title,
        //   desc:_desc
        // });
        let _contents=this.state.contents.concat({
          id:this.max_content_id+1,
          title:_title,
          desc:_desc
        });
        this.setState({
          contents:_contents
        });
      }}></CreateContent>
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={function(){
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }.bind(this)}></Subject> 
        <TOC data={this.state.contents} 
        onChangePage={id=>{
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }}></TOC> 
        <Control onChangeMode={_mode=>{this.setState({
            mode:_mode
        });}}></Control>
        {_article}
        {/* <ReadContent title={_title} desc={_desc}></ReadContent> */}
      </div>
      );
  }
}

export default App;

 

 

  • 3. Array.from 사용

import { Component } from 'react';
import './App.css';
import Subject from '../src/Components/Subject';
import TOC from '../src/Components/TOC'
import ReadContent from './Components/ReadContent'
import Control from '../src/Components/Control'
import CreateContent  from '../src/Components/CreateContent';

class App extends Component{
  constructor(props){
    super(props);
    this.max_content_id=3;
    this.state={
      mode:'read',
      selected_content_id:1,
      subject:{title:'웹카페',sub:'웹에 대해 알아봅시다'},
      welcome:{title:'환영합니다',desc:'웹카페 홈페이지 방문을 환영합니다'},
      contents:[ //배열 객체
      {id:1, title:'HTML5에 대해', desc:'홈페이지의 뼈대를 말한다'},
      {id:2, title:'CSS3의 모든 것', desc:'홈페이지를 꾸미고 레이아웃을 설정한다'},
      {id:3, title:'Javascript란', desc:'정적인 홈페이지를 동적으로 만든다'}
      ]
    }
  }

  render(){ //render: export 도움

    console.log('App 컴포넌트 렌더링됨');
    let _title, _desc, _article=null; //컴포넌트 담을 변수 앞에 _ 입력할 것
    if (this.state.mode==='welcome'){ 
      _title=this.state.welcome.title;
      _desc=this.state.welcome.desc;
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode==='read') {
      let i=0;
      while(i<this.state.contents.length){
        let data=this.state.contents[i];
        if (data.id===this.state.selected_content_id){
          _title=data.title;
          _desc=data.desc;
          break;
        }
        i++;
      }
      _article=<ReadContent title={_title} desc={_desc}></ReadContent>
    } else if (this.state.mode === 'create'){
      _article=<CreateContent submitValue={(_title,_desc)=>{ //위 같은 이름 변수와 다름 //외부에서 받는 매개변수임
        this.max_content_id=this.max_content_id+1;
        // this.state.contents.push({ 
        //   id:this.max_content_id+1,
        //   title:_title,
        //   desc:_desc
        // });
        /*let _contents=this.state.contents.concat({
          id:this.max_content_id+1,
          title:_title,
          desc:_desc
        });
        this.setState({
          contents:_contents
        });*/
        let _contents=Array.from(this.state.contents); //복제
          _contents.push({
          id:this.max_content_id,
          title:_title,
          desc:_desc
        });
        this.setState({
          contents:_contents
        });
      }}></CreateContent>
    }

    return ( 
      <div className='App'> 
        <Subject title={this.state.subject.title} 
        sub={this.state.subject.sub}
        onChangePage={()=>{
          //alert('클릭해서 속성 호출')
          this.setState({mode:'welcome'});
        }}></Subject> 
        <TOC data={this.state.contents} 
        onChangePage={id=>{
          this.setState({
            mode:'read',
            selected_content_id:Number(id)
          });
        }}></TOC> 
        <Control onChangeMode={_mode=>{this.setState({
            mode:_mode
        });}}></Control>
        {_article}
      </div>
      );
  }
}

export default App;

 

 

 

  • shouldComponentUpdate() : 성능 최적화 (리렌더링 횟수 감축)
  • TOC

import { Component } from 'react';

class TOC extends Component{
  shouldComponentUpdate(newProps, newState){ 
    console.log('TOC 컴포넌트에 도착',
    newProps.data, 
    this.props.data);
    if (newProps.data===this.props.data)//기존값=새로운 값 -> rendering 안 함  //push 쓰면 해당사항 true로 반환돼 기능 구현 불가
      return false;
    }
    return true;
  }

  render(){
    console.log('TOC 컴포넌트가 수정되어 렌더링됨');
    let lists=[];
    let data=this.props.data;
    let i=0;
    while(i<data.length){
      lists.push(<li key={data[i].id}><a 
      href={"/content/"+data[i].id} 
      data-id={data[i].id} 
      onClick={function(event){
        event.preventDefault(); 
        this.props.onChangePage(event.target.dataset.id);  
      }.bind(this)}>{data[i].title}</a></li>);
      i++;
    }

    return(
      <nav>
        <ul>
            {lists}
        </ul>
      </nav>
    );
  }
}

export default TOC;

 

 

=> 생성하기 누를 때도 실행되던 render이 실행 안 되도록 함