Skip to content
listing popular contents
JavaScript HTML CSS
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
backend
public
src
.gitignore
README.md
package.json

README.md

폴더구조

backend
	|_ server.js
	|_ package.json
public
	|_ index.html
src
	|_ actions
		|_ ActionTypes.js
		|_ index.js
	|_ components
		|_ App.js
		|_ ContentCard.js
		|_ ContentForm.js
		|_ ContentFormPage.js
		|_ ContentsList.js
		|_ ContentsPage.js
	|_ reducers
		|_ index.js
		|_ contents.js
	|_ index.css
package.json

초기화면

  • index.js 파일이 실행되면서 가장 최상위인 App 컴포넌트가 랜더링 됩니다.
  • 총 세 개의 페이지(Home, Content, Add New Content)에서 Home이 기본 페이지로 노출됩니다.
  • App.js 컴포넌트는 각 페이지의 링크에 맞춰 노출될 컴포넌트를 라우팅으로 설정해 놓습니다.
<div className="ui three item menu">
  <Link className="item" to="/">Home</Link>
  <Link className="item" to="/contents">Content</Link>
  <Link className="item" to="/contents/new">Add New Content</Link>
</div>
  <Route exact path="/contents" component={ContentsPage} />
  <Route path="/contents/new" component={ContentFormPage} />
  <Route path="/content/:_id" component={ContentFormPage} />
  • 각각의 path의 따라 랜더링되는 컴포넌트를 다르게 설정할 수 있습니다.
  • Content 를 클릭하면 url에 /contents 가 추가되면서 ContentsPage 가 랜더링됩니다.
  • ContentsPage는 두 개의 하위 컴포넌트를 가지고 있습니다 (ContentsList, ContentCard)
  • 여기서 중요한 건 일명 똑똑한 컴포넌트 (하위 컴포넌트를 보유하면서 서비스에서 중요한 역할을 하는 페이지)는 Redux와 연결하여 데이터의 사용을 좀 더 용이하게 할 수 있습니다. 아래와 같이 connect()(); 를 사용합니다.
export default connect(mapStateToProps,{fetchContents, deleteContent})(ContentsPage);
  • 그럼, ContentsPage 랜러딩 과정을 자세히 살펴 보도록 하겠습니다.
  • 우선 view 화면이 랜더링 되기 전에 componentDidMount() 가 먼저 실행 되면서 fetchContents() 액션함수가 실행됩니다. 이 함수가 먼저 실행되는 이유는 화면에 뿌려질 초기 데이터값을 가져오기 위해서 입니다.
  • 리액트에서 비동기 처리는 action에서 담당하며, 이때 axios라는 비동기 라이브러리를 사용할 수도 있으며, Fetch API 를 사용해서 서버와 통신을해도 됩니다.
  • /api/contents 을 인자로 받아 서버통신을 통해 데이터 베이스에 있는 데이터값을 가져와 json 파일로 리턴합니다.
app.get('/api/contents', (req, res) => {
    db.collection('contents').find({}).toArray((err, contents) => {
      res.json({ contents });
    });
  });
  • '뮤직' 앱은 서버는 Node.js, Express.js 를 데이터베이스는 mongoDB 를 사용하였습니다.
  • db.COLLECTION_NAME.find({}) 를 사용하여 기준없이 모든 다큐먼트를 조회한 후 toArray() 콜백함수를 실행하여 데이터를 전달합니다.
  • DB에서 서버를 통해 클라이언트로 전달된 데이터는 액션함수 setContents(data.contents) 의 인자로 넘어가면서 setContents의 SET_CONTENTS 타입과 contents 데이터값을 reducers 함수로 넘깁니다.
export const setContents = (contents) => {
  return {
    type: SET_CONTENTS,
    contents
  }
}
  • reducers 폴더에 있는 contents.js 는 전달된 타입에 맞는 case를 실행합니다. 이 과정에서 전체 데이터 값을 관리하는 state의 값이 업데이트 됩니다.
case SET_CONTENTS:
	return action.contents;
default: return state;
  • 데이터를 관리하는 state 객체의 상태가 변하면서 이 값을 공유하는 모든 하위 컴포넌트의 화면이 다시 랜더링 됩니다. 값을 전체 컴포넌트와 공유하기 위해서는 아래와 같은 설정이 필요합니다.
function mapStateToProps(state) {
	return {
		contents: state.contents
	}
}
  • 이 값은 this.props.contents 로 접근이 가능하며, 쉽게 생각하면 어디서든 접근이 가능한 전역변수라고 생각하시면 됩니다.
  • 이 값은 최종적으로 ContentCard 컴포넌트까지 전달되며, 이때 map()을 사용해 데이터에 포함된 모든 뮤직 값을 화면에 출력합니다.
{ contents.map(content => <ContentCard content={content} key={content._id} deleteContent={deleteContent}/>) }

카드추가

  • /contents/new 클릭 이동 후 ContentFormPage 페이지 랜더링 됩니다.
  • validation을 통과 후 save 버튼을 클릭하면 id, title, cover 값을 state 에서 가져옵니다.
  • 다음으로 상위 컴포넌트에서 전달된 saveContent 함수가 실행되면서 saveContent 액션함수가 실행되면서 api요청을 하게 됩니다.
  • 전달된 값은 db에 저장이 되고 redirect: true 로 변환시킵니다.
  • redirect 의 값이 true 이기 때문에 최종적으로 contentsPage 가 랜더링됩니다.

카드수정

  • 카드수정은 ContentCard 의 Edit 를 누르면 content의 id 값을 이용합니다.
<Link to={`/content/${content._id}`} className="ui basic button green">Edit</Link>
  • 화면 랜더링 시 각각의 카드에는 고유의 id값이 부여되어 있습니다. Edit 링크를 클릭하면 라우터에 의해 ContentFormPage 이 랜더링 됩니다.
<Route path="/content/:_id" component={ContentFormPage} />
  • 랜러딩 전에 라우트로 넘어온 파라미터에 접근하여 id 값을 가져오며 (this.props.match.params) 이 값은 fetchContent() 액션의 인자로 전달 됩니다.
componentDidMount = () => {
	    if (this.props.match.params._id) {
	      this.props.fetchContent(this.props.match.params._id);
	    }
  	}
  • api 요청으로 현재 선택된 id값의 정보가 db 에서 전달됩니다. findOne() 은 배열의 가장 첫번째 위치한 데이터를 추출합니다.
  • 추출된 데이터는 this.props.content 로 ContentForm 으로 전달됩니다. 이 값의 유뮤에 따라 랜더링 화면이 달라집니다.
You can’t perform that action at this time.