정보실

웹학교

정보실

Reactjs React를 사용하여 대화식 목록을 작성하기 위한 초보자 안내서

본문

이 문서는 React를 사용하여 대화식 목록을 작성하는 방법에 대한 초보자 용 단계별 자습서입니다. 

https://medium.com/better-programming/the-beginners-guide-to-creating-an-interactive-list-with-react-28c8af880f35 


Create a React App 


Facebook의 스크립트 create-react-app는 React 프로젝트를 시작하는 기본 방법입니다. 

그러나 배포 할 때는 지원되지 않습니다. 이를 위해 Infrastructure-Components를 사용할 수 있습니다. 

이러한 React 컴포넌트를 사용하면 인프라 아키텍처를 React 앱의 일부로 정의 할 수 있습니다. 

즉, Webpack, Babel 또는 Serverless와 같은 다른 구성은 더 이상 필요하지 않습니다.


프로젝트를 설정할 수 있는 세 가지 방법이 있습니다.

다음과 같은 파일 구조가 제공됩니다.


menu/
├── src/
│ └── index.tsx
├── .env
├── .gitignore
├── LICENSE
├── package.json
└── README 


package.json은 프로젝트의 모든 종속성을 지정합니다. 

이 튜토리얼에서는 npm install을 통해 설치된 다음 라이브러리를 사용합니다.


"dependencies": {
"infrastructure-components": "^0.3.1",
"react": "^16.10.2",
"react-dom": "^16.10.2",
"react-sortable-hoc": "^1.10.1",
"styled-components": "^4.1.3"
},
"devDependencies": {
"infrastructure-scripts": "^0.3.1",
"serverless-single-page-app-plugin": "^1.0.2"
} 


가장 중요한 파일은 src/index.tsx 파일입니다. 이것이 React 앱의 진입점입니다. 이 파일에서 <SinglePageApp /> 구성 요소를 내 보냅니다. src/index.tsx 파일이 준비되면 처음에 프로젝트를 빌드할 수 있습니다 (npm run build).


import React from 'react';

import {
    Environment,
    Route,
    SinglePageApp
} from "infrastructure-components";

export default (
    <SinglePageApp
        stackName = "interactive-list"
        buildPath = 'build'
        region='us-east-1'>

        <Environment name="dev" />

        <Route
            path='/'
            name='Infrastructure-Components'
            render={()=><div>Hello Infrastructure-Components!</div>}
        />

    </SinglePageApp>
);

기본 서버리스 단일 페이지 React 앱의 소스 코드


빌드 단계는 package.json에 명령을 추가합니다. 이 명령은 단일 페이지 앱을 핫 개발 모드로 시작합니다. 

npm run interactive-list (interactive-list를 단일 페이지 앱 이름으로 바꿉니다). 

브라우저에서 localhost:3000을 열면“Hello Infrastructure-Components!”라는 텍스트가 표시됩니다.


새 파일에 src/list.tsx라는 세 가지 항목이 포함 된 간단한 순서 없는 목록을 만들어 보겠습니다. 각 항목에는 확인란이 있습니다.


import React from 'react';

export default function () {
    return <ul>
        <li>First Item</li>
        <li>Second Item</li>
        <li>Third Item</li>
    </ul>
};

목록 구성 요소 (src/list.tsx)


기본 함수를 list.tsx로 내보내므로 index.tsx의 모듈에서 기본값을 가져와야 합니다. 우리는 이것을 9 행에서 수행합니다. 22 행에서 가져온 구성 요소를 렌더링 합니다.


import React from 'react';

import {
    Environment,
    Route,
    SinglePageApp
} from "infrastructure-components";

import List from './list';

export default (
    <SinglePageApp
        stackName = "interactive-list"
        buildPath = 'build'
        region='us-east-1'>

        <Environment name="dev" />

        <Route
            path='/'
            name='Infrastructure-Components'
            render={()=><List/>}
        />

    </SinglePageApp>
);

인덱스에 List 통합


다음 이미지는 우리의 목록을 보여줍니다. 지금까지 놀라운 것은 없습니다.


1*4DYn1uH7wl-M9RyPaCEQ9A.png인터랙티브 스타일 


React에서 스타일을 관리하는 가장 편리한 방법은 styled components 라이브러리를 사용하는 것입니다. styled components는 로컬 CSS 리터럴을 통해 구성 요소에 반응하여 스타일을 보자.


첫 번째 styled components를 살펴 보겠습니다. 변경되지 않은 코드 부분은 건너 뜁니다.


/* ...*/ 
import styled from 'styled-components'

const Item = styled.li`
  display: block;
  border-top: 1px solid #888;
  list-style-type: none;
  padding: 5px 0;
  &:hover {
      background: #EEE;
  }  
`;

export default function () {
    return <ul>
        <Item>First Item</Item>
        <Item>Second Item</Item>
        <Item>Third Item</Item>
    </ul>
};

아이템 스타일링


먼저 라이브러리에서 기본 모듈 (스타일)을 가져옵니다. 스타일 모듈은 스타일 구성 요소 라이브러리의 기본 내보내기입니다. 이것은 styled.tagname 형식의 헬퍼 메소드를 제공하는 저수준 팩토리입니다.


태그 이름은 유효한 HTML 태그입니다. 예를 들어 styled.li는 목록 항목 구성 요소 (<li />)를 만듭니다. styled.li 함수는 템플릿 문자열 (백틱으로`...`으로 묶음)으로 CSS 정의를 가져옵니다.


그런 다음 Item 구성 요소 (<li />)를 만들어 간단한 스타일을 적용합니다. 형식화 컨텍스트를 표시하도록 설정하십시오 : block ;. 블록 형식화 컨텍스트에서 구성 요소는 차례로 수직으로 배치됩니다. 각 구성 요소의 외부 모서리는 포함 블록의 모서리에 닿습니다. 간단히 말해 : 컴포넌트가 전체 라인을 차지하게 합니다.


각 항목은 상단에 가는 (1px) 회색 (컬러 # 888) 테두리를 갖습니다. 그리고 번호가 매겨지지 않은 리스트 요소들이 일반적으로 가지고 있는 점을 제거합니다 (list-style-type : none;).


패딩 : 5px 0; 위쪽과 아래쪽의 (내부) 공간 영역을 5px로 설정하고 구성 요소의 왼쪽과 오른쪽에서 0으로 설정합니다.


대화식 스타일을 추가하겠습니다. & : 호버 {배경 : #EEE}는 사용자가 마우스 포인터로 항목을 가리킬 때 항목의 배경을 밝은 회색으로 설정합니다.


내 보낸 컴포넌트에서 스타일이 없는 <li /> 요소를 스타일이 지정된 <Item /> 컴포넌트로 바꿉니다.


이 단계에서는 스타일을 목록에 적용하고 헤더를 추가하여 변경되지 않은 부분을 다시 건너 뜁니다.


/* ...*/ 
const List = styled.ul`
    margin: auto;
    width: calc(100% - 20px);
    padding-left: 0;
`;

const Header = styled.li`
    padding: 5px;
    color: #888;
    font-weight: bold;
    list-style-type: none;
`;

export default function () {
    return <List>
        <Header>Name</Header>
        <Item>First Item</Item>
        <Item>Second Item</Item>
        <Item>Third Item</Item>
    </List>
};

리스트 스타일링


<List /> 컴포넌트 (<ul />)가 약간의 공간을 제외하고 브라우저의 전체 너비를 채우길 원합니다. 너비를 100 %에서 남겨두고 싶은 공간을 뺀 값으로 20px로 설정하면 됩니다. (참고 : calc 함수 내에서“-”기호 앞뒤에 공백이 있어야 합니다). 여백 : 자동; 나머지 (외부) 공간을 균등하게 분배하므로 목록의 중앙에 위치합니다. 동일한 결과를 얻는 다른 방법도 있습니다.


다른 스타일은 지금까지 설명이 필요합니다.


우리의 앱을 살펴 봅시다 :



1*HUxe6l8iNYg7td2LUENAKw.png 

스크린 샷에 마우스가 없습니다… 그러나 두 번째 항목 위에 있음을 확인할 수 있습니다


고급 사용자 상호 작용 


React 앱의 시각적 및 대화 형 기능은 CSS 스타일을 구성 요소에 적용하는 것 이상의 기능을 합니다. 드래그 앤 드롭 동작이 예입니다. 끌어서 놓기는 웹 및 모바일 응용 프로그램에서 요소를 이동하고 재배 열하는 직관적 인 방법입니다. 포인터 (마우스 또는 터치) 이벤트를 수신하고 데이터에 대해 작업하며 DOM을 변경합니다.


끌어서 놓기는 HTML5의 일부입니다 (여기에서 설명). 따라서 저수준 HTML5 API를 기반으로 이 제스처를 앱에 추가 할 수 있습니다. 그러나 이 제스처를 프로그래머에게 친숙한 고급 API로 래핑하는 라이브러리는 상당히 많습니다. react-sortable-hoc가 좋은 예입니다. 모든 목록을 애니메이션적이고 터치하기 쉽고 정렬 가능한 목록으로 변환하는 일련의 상위 React 구성 요소를 제공합니다.


고차 React 컴포넌트 (HOC)는 컴포넌트 로직 재사용을 위한 React의 고급 기술입니다. 일반적으로 React 구성 요소는 속성을 링크, 목록 또는 다른 HTML 요소와 같이 보이는 것으로 변환합니다. 고차 컴포넌트는 한 컴포넌트를 다른 컴포넌트로 변경하는 기능을 추가합니다.


고차 컴포넌트 리액터 정렬 가능-호크를 사용하여 컴포넌트에 끌어서 놓기 기능을 추가 할 수 있습니다.


그러나 드래그 앤 드롭 기능을 목록에 추가하기 전에 레이아웃과 데이터를 분리해야 합니다. 현재 데이터 (항목 이름)가 시각적 React 구성 요소에 혼합되어 있습니다. 모든 단일 항목은 <Item> Hard-coded Item Name </ Item>으로 하드 코딩됩니다. 이것은 유연하거나 확장 할 수 없습니다.


다음은 레이아웃과 데이터를 분리하는 방법을 보여줍니다.


/* ...*/ 
export default function () {
    const items = ["First Item", "Second Item", "Third Item"];

    return <List>
        <Header>Name</Header>
        {
            items.map((item, index) => (
                <Item key={`item-${index}`}>{item}</Item>
            ))
        }
    </List>
}

list.tsx에서 레이아웃과 데이터 분리


내 보낸 함수 내에서 상수 항목을 정의합니다. 이것은 문자열의 배열입니다. 이전에 <Item /> 구성 요소 내에 하드 코딩 한 데이터입니다.


줄 7과 11 사이의 코드 블록에서 분리 된 데이터 (항목 배열)를 <Item />-구성 요소로 다시 통합합니다. 배열은 맵 기능을 제공합니다. 이 함수는 각 배열의 항목을 가져 와서 인수로 제공하는 함수에 따라 변환 한 다음 결과를 새 배열로 반환합니다. 원래 배열은 변경되지 않습니다.


인수로 제공하는 함수는 8 행에서 시작합니다. 이름이 없는 익명 함수이며 화살표 표기법을 따릅니다. (인수) => ( "반환 된 결과").


우리는 두 개의 인수 item과 index를 사용합니다. 이 두 가지 주장의 이름은 우리에게 달려 있지만 그들의 입장은 중요합니다. 첫 번째 인수는 현재 항목입니다. 이것은 문자열입니다. 두 번째 인수는 배열 내 현재 항목의 색인입니다.


items 배열에 세 개의 항목이 있으므로 map 함수는 제공된 함수를 세 번 호출합니다. 먼저 item = "First Item"및 index = 0 인수를 사용하십시오. 그런 다음 item = "Second Item"인수와 index = 1을 사용하십시오. 마지막으로… 수학을 할 수 있다고 생각합니다.


이 함수는 이 두 인수를 변환하고 <Item /> 구성 요소를 반환합니다. {item}을 표시 가능한 컨텐츠로 지정하고 문자열 ( "item-0"및 item-1)을 키 특성 값으로 지정합니다. 기술적 인 이유가 있습니다. JSX에서 배열을 반환하는 코드 블록을 제공 할 때 (예 : map 함수처럼) React는 각 배열의 항목에 고유 한 키 속성을 제공해야 합니다.


앱을 실행하면 차이가 없어야 합니다. 그러나 이제 레이아웃에 없는 모든 데이터를 배열에 담았습니다. 반응 정렬 가능 라이브러리를 통해 드래그 앤 드롭 기능을 추가 할 준비가 되었습니다. 먼저 코드를 살펴 봅시다 :


/* ...*/
import {SortableContainer, SortableElement} from 'react-sortable-hoc';
const SortableItem = SortableElement(Item);

const SortableList = SortableContainer(props => {
    return (
        <List>
            <Header>Name</Header>
            {
                props.items.map((item, index) => (
                    <SortableItem key={`item-${index}`} index={index}>{item}</SortableItem>
                ))
            }
        </List>
    );
});

export default function () {
    const items = ["First Item", "Second Item", "Third Item"];

    return <SortableList items={items}/>;
};

드래그 앤 드롭 기능 추가


2 행에서 우리는 SortableContainer와 SortableElement라는 두 가지 고차 컴포넌트를 가져옵니다.


SortableElement 함수는 구성 요소를 드래그 가능하게 만듭니다. 3 번째 줄에서 SortableElement는 Item 함수를 인수로 사용하고 유사한 드래그 가능한 함수를 반환합니다 (참고 : <Item />에서 렌더링 된 구성 요소로 제공하지 마십시오).


SortableContainer 함수는 드래그 가능한 자식을 포함하도록 부모 구성 요소를 준비합니다. 이전과 마찬가지로 List 함수를 전달할 수 있습니다. 그러나 다른 방법이 있습니다. 한번 보자.


React 함수는 속성을 다음과 같이 보이는 것으로 변환합니다. 

const Component = (props) => <div />.


상위 구성 요소는 구성 요소 (Component) 또는 해당 본문 ((props) => <div />)의 함수 선언 (이름)을 승인합니다. 5 행에서 후자의 형식을 사용합니다. 소품을 가져 와서 <Header />와 매핑 된 항목 배열을 사용하여 <List />로 변환합니다.


소품에는 아이템 만 포함될 것으로 예상됩니다. 내 보낸 함수에서 렌더링 된 <SortableList />를 반환 할 때 items 배열을 제공합니다. 결과는 간결한 내보내기 기능입니다. 모든 조각 관련 논리는 <SortableList /> 구성 요소에 유지됩니다.


11 번째 줄에서 인덱스 속성을 <SortableFile />에 추가했습니다. react-sortable-hoc 라이브러리에 필요한 배열 내 요소의 sortableIndex입니다.


앱을 보면 이제 두 파일을 드래그 할 수 있습니다. 그러나 일단 떨어 뜨리면 원래 위치로 돌아갑니다. 물론 아이템 배열이 변경되지 않기 때문에 변경됩니다.


1*FkP5QTmzlTZsFsU9OAS3gQ.gif 



Local Component State 


react-sortable-hoc의 참조를 보면 SortableContainer HOC가 onSortEnd-property를 <List />에 추가한다는 것을 알 수 있습니다. 이 속성은 정렬이 끝날 때 호출되는 인수로 함수를 사용합니다. 드래그 한 항목의 oldIndex와 newIndex를받습니다.


그러나 아이템 배열을 어떻게 변경합니까? 불변의 const입니다. React가 구성 요소를 렌더링 할 때마다 새로 시작하기 때문에 변경 가능한 var로 변경하면 도움이 되지 않습니다. 변수의 값을 "기억"하지 않습니다. React가 컴포넌트를 다시 렌더링 하지 않으면 변경 사항이 표시되지 않습니다.


해결책은 useState React 후크입니다 (React 16.8.0부터 지원됨). 후크는 구성 요소에 재사용 가능한 동작을 "연결"하는 방법을 제공합니다. 따라서 후크는 고차 부품과 유사합니다. 그러나 고차 컴포넌트는 외부 랩퍼가 필요하므로 컴포넌트 계층 구조를 변경하는 반면 후크를 사용하면 로직을 변경하지 않고도 재사용 할 수 있습니다.


다음 코드는 목록에 상태를 추가합니다.


import React, {useState} from 'react';
/* ...*/
export default function () {
    const [items, setItems] = useState(["First Item", "Second Item", "Third Item"]);

    return <SortableList items={items} onSortEnd={
        ({oldIndex, newIndex}) => {
            const removed = items.slice(0, oldIndex)
                .concat(items.slice(oldIndex+1));
                
            setItems(
                removed.slice(0,newIndex)
                    .concat([items[oldIndex]])
                    .concat(removed.slice(newIndex))
            );
        }
    }/>
};

useState 후크 추가


useState는 함수입니다. 반응에서 가져 와서 4 행에서 사용합니다. 단일 인수가 필요합니다. 이것이 초기 상태입니다. 따라서 이전에 items 배열에 넣은 것과 동일한 데이터를 제공합니다.


useState는 두 개의 요소가 있는 배열을 반환합니다. 첫 번째 요소는 현재 상태입니다. 변경하지 않았으므로 초기 상태 인 항목 배열입니다. 이전과 같이 사용합니다. 6 행에서 이를 <SortableList /> 컴포넌트에 특성으로 제공합니다.


새로운 것은 두 번째 요소입니다. 상태를 설정하는 기능입니다. 임의의 이름을 사용할 수 있습니다. 그것을 setItems라고 부르겠습니다. 우리는 11 번째 줄의 onSortEnd 함수에서이 함수를 사용합니다. 업데이트 된 항목 순서로 새 항목 배열을 제공합니다.


8 행에서 파일을 드래그 하지 않고 새로운 임시 배열을 만듭니다. 배열의 슬라이스 함수는 배열의 일부를 반환합니다. slice의 두 매개 변수는 시작과 끝의 색인을 지정합니다 (끝은 포함되지 않음). 배열의 concat 함수는 두 배열을 연결합니다. 따라서 하위 배열을 처음부터 드래그 한 항목 (제외됨)으로 가져 와서 드래그 된 항목 이후부터 끝까지 하위 배열에 연결합니다 (9 행에서와 같이 단일 인수로 슬라이스를 호출 할 때).


우리는 새로운 위치로 처음부터 이 임시 배열을 슬라이스 (원래 항목의 배열에서 촬영) 항목을 끌고와 연결하고, 임시 배열의 나머지 부분과 연결합니다. 이것은 우리가 setItems 함수에 제공하는 재정렬 된 아이템 배열입니다.


4 행에 오류가 있습니까? 아이템 배열을 const로 선언했습니다. 그러나 당신은 const를 바꿀 수 없습니다!


setItems 함수는 이러한 값을 변경하지 않습니다. React가 새로운 값으로 사용자 인터페이스를 다시 렌더링하게 합니다. React는 이전 <SortableList />를 새 것으로 대체합니다. 새로운 <SortableList />에는 고유 한 불변 항목 배열이 있습니다. 현재 상태 만 알고 있습니다. 과거 상태는 중요하지 않으며 상태가 어떻게 생성되었는지도 중요하지 않습니다.


이제 대화식 목록을 살펴 보겠습니다.


1*AnrOXxONn37ePIn2vduaDA.gif 

작동하는 대화식 목록.


전체 목록은 다음과 같습니다 .tsx :


import React, { useState } from 'react';

import styled from 'styled-components'
import {SortableContainer, SortableElement} from 'react-sortable-hoc';

const List = styled.ul`
    margin: auto;
    width: calc(100% - 20px);
    padding-left: 0;
`;

const Header = styled.li`
    padding: 5px;
    color: #888;
    font-weight: bold;
    list-style-type: none;
`;

const Item = styled.li`
  display: block;
  border-top: 1px solid #888;
  list-style-type: none;
  padding: 5px 0;
  &:hover {
      background: #EEE;
  }  
`;

const SortableItem = SortableElement(Item);

const SortableList = SortableContainer(props => {
    return (
        <List>
            <Header>Name</Header>
            {
                props.items.map((item, index) => (
                    <SortableItem key={`item-${index}`} index={index}>{item}</SortableItem>
                ))
            }
        </List>
    );
});

export default function () {
    const [items, setItems] = useState(["First Item", "Second Item", "Third Item"]);

    return <SortableList items={items} onSortEnd={
        ({oldIndex, newIndex}) => {
            const removed = items.slice(0, oldIndex)
                .concat(items.slice(oldIndex+1));

            setItems(
                removed.slice(0,newIndex)
                    .concat([items[oldIndex]])
                    .concat(removed.slice(newIndex))
            );
        }
    }/>
};

GitHub 리포지토리에서 전체 소스 코드를 찾을 수 있습니다.



  • 트위터로 보내기
  • 페이스북으로 보내기
  • 구글플러스로 보내기
  • 카카오톡으로 보내기

페이지 정보

조회 19회 ]  작성일19-12-05 21:18

웹학교