React
구성 요소
수색…
비고
React.createClass
는 React.createClass
에서 사용되지 않으며 v16 에서 제거 될 것으로 예상됩니다. 여전히 필요한 패키지를 위한 드롭 인 대체 패키지 가 있습니다. 이를 사용하는 예제가 업데이트되어야합니다.
기본 구성 요소
주어진 다음 HTML 파일 :
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>React Tutorial</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/babel" src="scripts/example.js"></script>
</body>
</html>
별도의 파일에 다음 코드를 사용하여 기본 구성 요소를 만들 수 있습니다.
scripts / example.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class FirstComponent extends Component {
render() {
return (
<div className="firstComponent">
Hello, world! I am a FirstComponent.
</div>
);
}
}
ReactDOM.render(
<FirstComponent />, // Note that this is the same as the variable you stored above
document.getElementById('content')
);
다음과 같은 결과를 얻게 될 것입니다 ( div#content
).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>React Tutorial</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
</head>
<body>
<div id="content">
<div className="firstComponent">
Hello, world! I am a FirstComponent.
</div>
</div>
<script type="text/babel" src="scripts/example.js"></script>
</body>
</html>
중첩 구성 요소
ReactJS의 많은 힘은 구성 요소의 중첩을 허용하는 능력입니다. 다음 두 가지 구성 요소를 가져옵니다.
var React = require('react');
var createReactClass = require('create-react-class');
var CommentList = reactCreateClass({
render: function() {
return (
<div className="commentList">
Hello, world! I am a CommentList.
</div>
);
}
});
var CommentForm = reactCreateClass({
render: function() {
return (
<div className="commentForm">
Hello, world! I am a CommentForm.
</div>
);
}
});
다른 구성 요소의 정의에서 해당 구성 요소를 중첩하거나 참조 할 수 있습니다.
var React = require('react');
var createReactClass = require('create-react-class');
var CommentBox = reactCreateClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList /> // Which was defined above and can be reused
<CommentForm /> // Same here
</div>
);
}
});
추가 네 스팅은 세 가지 방법으로 수행 할 수 있으며, 모두 세 가지 방법으로 사용할 수 있습니다.
1. 아이들을 사용하지 않고 중첩
(위에서 계속)
var CommentList = reactCreateClass({
render: function() {
return (
<div className="commentList">
<ListTitle/>
Hello, world! I am a CommentList.
</div>
);
}
});
이것은 A가 B를 구성하고 B가 C를 구성하는 스타일입니다.
찬성
- 쉽고 빠른 UI 요소 분리
- 상위 구성 요소의 상태를 기반으로 소품을 어린이에게 쉽게 주입 할 수 있습니다.
단점
- 컴포지션 아키텍처에 대한 가시성이 낮습니다.
- 재사용 성 감소
만약 그렇다면
- B와 C는 단지 프리젠 테이션 구성 요소입니다.
- B가 C의 수명주기를 책임 져야 함
2. 아이들을 이용한 중첩
(위에서 계속)
var CommentBox = reactCreateClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList>
<ListTitle/> // child
</CommentList>
<CommentForm />
</div>
);
}
});
이것은 A가 B를 구성하고 A가 B에 C를 작성하도록 지시하는 스타일입니다. 상위 구성 요소에 더 많은 기능이 있습니다.
찬성
- 더 나은 구성 요소 라이프 사이클 관리
- 컴포지션 아키텍처에 대한 더 나은 가시성
- 더 나은 재사용 성
단점
- 주사기를 조금씩 비싸게 만들 수 있습니다.
- 하위 구성 요소의 유연성 및 전력 감소
만약 그렇다면
- 미래에 또는 다른 곳에서 C와 다른 것을 작성하려면 B가 동의해야합니다.
- A는 C의 수명주기를 제어해야합니다.
B는 this.props.children
사용하여 C를 렌더링하며, B가 해당 자식이 무엇인지 알 수있는 구조화 된 방법이 없습니다. 따라서 B는 추가 소품을 제공하여 하위 구성 요소를 풍부하게 만들 수 있지만 B가 정확하게 무엇인지 파악해야하는 경우 # 3이 더 나은 옵션 일 수 있습니다.
3. 소품을 사용하여 중첩
(위에서 계속)
var CommentBox = reactCreateClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList title={ListTitle}/> //prop
<CommentForm />
</div>
);
}
});
이것은 A가 B를 구성하는 스타일이고 B는 A가 특정 목적을 위해 작성하는 것을 전달하는 옵션을 제공합니다. 더 구조화 된 구성.
찬성
- 기능으로 구성
- 간편한 검증
- 더 나은 작곡
단점
- 주사기를 조금씩 비싸게 만들 수 있습니다.
- 하위 구성 요소의 유연성 및 전력 감소
만약 그렇다면
- B에는 뭔가를 구성하기 위해 정의 된 특정 기능이 있습니다.
- B는 무엇을 렌더링 할 것인지 알 수 있어야합니다.
# 3은 일반적으로 구성 요소의 공용 라이브러리를 만들기위한 필수 요소 일뿐만 아니라 일반적으로 구성 가능한 구성 요소를 만들고 구성 기능을 명확하게 정의하는 좋은 방법입니다. # 1은 효과가있는 것을 만드는 데 가장 쉽고 빠르지 만 # 2와 # 3은 다양한 유스 케이스에서 특정 이점을 제공해야합니다.
구성 요소 만들기
이것은 기본 예제의 확장입니다.
기본 구조
import React, { Component } from 'react';
import { render } from 'react-dom';
class FirstComponent extends Component {
render() {
return (
<div>
Hello, {this.props.name}! I am a FirstComponent.
</div>
);
}
}
render(
<FirstComponent name={ 'User' } />,
document.getElementById('content')
);
위의 예제는 상태를 포함하지 않으므로 상태 비 저장 구성 요소라고 불립니다 (단어의 반응 감각에서).
이 경우 ES6 화살표 함수를 기반으로하는 Stateless Functional Components를 사용하는 것이 더 바람직하다고 생각하는 사람들이 있습니다 .
무국적 기능 구성 요소
많은 응용 프로그램에는 상태를 유지하지만 JSX로 HTML을 반환하는 단순한 구성 요소를 렌더링하는 스마트 구성 요소가 있습니다. 상태 비 저장 기능 구성 요소는 훨씬 더 재사용 가능하며 응용 프로그램에 긍정적 인 성능 영향을 미칩니다.
그들에는 2 개의 주요 특성이있다 :
- 렌더링 될 때 그들은 전달 된 모든 소품이있는 객체를받습니다.
- 렌더링 할 JSX를 반환해야합니다.
// When using JSX inside a module you must import React
import React from 'react';
import PropTypes from 'prop-types';
const FirstComponent = props => (
<div>
Hello, {props.name}! I am a FirstComponent.
</div>
);
//arrow components also may have props validation
FirstComponent.propTypes = {
name: PropTypes.string.isRequired,
}
// To use FirstComponent in another file it must be exposed through an export call:
export default FirstComponent;
상태 저장 구성 요소
위에 표시된 'stateless'구성 요소와 달리 'stateful'구성 요소에는 setState
메소드로 업데이트 할 수있는 상태 객체가 있습니다. 상태를 설정하기 전에 constructor
에서 상태를 초기화해야합니다.
import React, { Component } from 'react';
class SecondComponent extends Component {
constructor(props) {
super(props);
this.state = {
toggle: true
};
// This is to bind context when passing onClick as a callback
this.onClick = this.onClick.bind(this);
}
onClick() {
this.setState((prevState, props) => ({
toggle: !prevState.toggle
}));
}
render() {
return (
<div onClick={this.onClick}>
Hello, {this.props.name}! I am a SecondComponent.
<br />
Toggle is: {this.state.toggle}
</div>
);
}
}
와 구성 요소를 확장 PureComponent
대신 Component
자동으로 실행됩니다 shouldComponentUpdate()
얕은 소품과 국가 비교와 라이프 사이클 방법. 이렇게하면 불필요한 렌더링이 줄어들어 응용 프로그램이 더 효율적으로 유지됩니다. 이것은 여러분의 구성 요소가 'Pure'이고 항상 동일한 상태와 소품 입력으로 동일한 출력을 렌더링한다고 가정합니다.
고차원 구성 요소
고차원 구성 요소 (HOC)를 사용하면 구성 요소 기능을 공유 할 수 있습니다.
import React, { Component } from 'react';
const PrintHello = ComposedComponent => class extends Component {
onClick() {
console.log('hello');
}
/* The higher order component takes another component as a parameter
and then renders it with additional props */
render() {
return <ComposedComponent {...this.props } onClick={this.onClick} />
}
}
const FirstComponent = props => (
<div onClick={ props.onClick }>
Hello, {props.name}! I am a FirstComponent.
</div>
);
const ExtendedComponent = PrintHello(FirstComponent);
고차원 구성 요소는 렌더링 방식에 관계없이 여러 구성 요소에서 논리를 공유하려는 경우에 사용됩니다.
setState 함정
비동기 컨텍스트에서 setState
를 사용할 때는주의해야합니다. 예를 들어 get 요청의 콜백에서 setState
를 호출하려고 할 수 있습니다.
class MyClass extends React.Component {
constructor() {
super();
this.state = {
user: {}
};
}
componentDidMount() {
this.fetchUser();
}
fetchUser() {
$.get('/api/users/self')
.then((user) => {
this.setState({user: user});
});
}
render() {
return <h1>{this.state.user}</h1>;
}
}
이것은 문제를 호출 할 수 있습니다. Component
가 마운트 해제 된 후에 콜백이 호출되면 this.setState
는 함수가 아닙니다. 이 경우 항상 setState
의 사용을 취소 할 수 있도록주의해야합니다.
이 예에서는 구성 요소가 분리 될 때 XHR 요청을 취소 할 수 있습니다.
class MyClass extends React.Component {
constructor() {
super();
this.state = {
user: {},
xhr: null
};
}
componentWillUnmount() {
let xhr = this.state.xhr;
// Cancel the xhr request, so the callback is never called
if (xhr && xhr.readyState != 4) {
xhr.abort();
}
}
componentDidMount() {
this.fetchUser();
}
fetchUser() {
let xhr = $.get('/api/users/self')
.then((user) => {
this.setState({user: user});
});
this.setState({xhr: xhr});
}
}
비동기 메소드는 상태로 저장됩니다. componentWillUnmount
에서 XHR 요청 취소와 같은 모든 정리를 수행합니다.
좀 더 복잡한 것을 할 수도 있습니다. 이 예제에서는이 객체를 인수로 받아들이고 함수 cancel
이 호출되면 this.setState
방지하는 'stateSetter'함수를 만듭니다.
function stateSetter(context) {
var cancelled = false;
return {
cancel: function () {
cancelled = true;
},
setState(newState) {
if (!cancelled) {
context.setState(newState);
}
}
}
}
class Component extends React.Component {
constructor(props) {
super(props);
this.setter = stateSetter(this);
this.state = {
user: 'loading'
};
}
componentWillUnmount() {
this.setter.cancel();
}
componentDidMount() {
this.fetchUser();
}
fetchUser() {
$.get('/api/users/self')
.then((user) => {
this.setter.setState({user: user});
});
}
render() {
return <h1>{this.state.user}</h1>
}
}
이것은 우리가 만든 setState
클로저에서 cancelled
변수가 보이기 때문에 효과가 있습니다.
소품
소품은 정보를 React 구성 요소에 전달하는 방법이며 기능을 포함하여 모든 유형을 가질 수 있습니다. 콜백이라고도합니다.
JSX에서 속성 구문과 함께 전달됩니다
<MyComponent userID={123} />
MyComponent에 대한 정의 내에서 userID는 이제 props 객체에서 액세스 할 수 있습니다.
// The render function inside MyComponent
render() {
return (
<span>The user's ID is {this.props.userID}</span>
)
}
모든 props
, 소속 유형 및 적용 가능한 경우 기본값을 정의하는 것이 중요합니다.
// defined at the bottom of MyComponent
MyComponent.propTypes = {
someObject: React.PropTypes.object,
userID: React.PropTypes.number.isRequired,
title: React.PropTypes.string
};
MyComponent.defaultProps = {
someObject: {},
title: 'My Default Title'
}
이 예에서 prop someObject
는 선택 사항이지만 prop userID
가 필요합니다. userID
를 MyComponent
에 제공하지 못하면 런타임시 React 엔진에 필요한 소품이 제공되지 않았다는 경고 메시지가 콘솔에 표시됩니다. 그러나이 경고는 React 라이브러리의 개발 버전에만 표시되며, 생산 버전에서는 경고를 기록하지 않습니다.
defaultProps
사용하면 단순화 할 수 있습니다.
const { title = 'My Default Title' } = this.props;
console.log(title);
에
console.log(this.props.title);
또한 object
array
및 functions
사용에 대한 보호 수단이기도 functions
. 객체에 기본 소품을 제공하지 않으면 소품이 전달되지 않으면 다음과 같은 오류가 발생합니다.
if (this.props.someObject.someKey)
위 예제에서 this.props.someObject
는 undefined
으므로 someKey
를 검사하면 오류가 발생하고 코드가 중단됩니다. defaultProps
를 사용하면 위의 검사를 안전하게 사용할 수 있습니다.
구성 요소 상태 - 동적 사용자 인터페이스
우리는 다음과 같은 동작을 원한다고 가정합니다 - 우리는 표제를 가지고 있습니다 (h3 요소를 말합니다). 그리고 이것을 클릭하면 표제 이름을 수정할 수 있도록 입력 상자가되기를 원합니다. React를 사용하면 구성 요소 상태 및 if 문을 사용하여 매우 간단하고 직관적입니다. (아래 코드 설명)
// I have used ReactBootstrap elements. But the code works with regular html elements also
var Button = ReactBootstrap.Button;
var Form = ReactBootstrap.Form;
var FormGroup = ReactBootstrap.FormGroup;
var FormControl = ReactBootstrap.FormControl;
var Comment = reactCreateClass({
getInitialState: function() {
return {show: false, newTitle: ''};
},
handleTitleSubmit: function() {
//code to handle input box submit - for example, issue an ajax request to change name in database
},
handleTitleChange: function(e) {
//code to change the name in form input box. newTitle is initialized as empty string. We need to update it with the string currently entered by user in the form
this.setState({newTitle: e.target.value});
},
changeComponent: function() {
// this toggles the show variable which is used for dynamic UI
this.setState({show: !this.state.show)};
},
render: function() {
var clickableTitle;
if(this.state.show) {
clickableTitle = <Form inline onSubmit={this.handleTitleSubmit}>
<FormGroup controlId="formInlineTitle">
<FormControl type="text" onChange={this.handleTitleChange}>
</FormGroup>
</Form>;
} else {
clickabletitle = <div>
<Button bsStyle="link" onClick={this.changeComponent}>
<h3> Default Text </h3>
</Button>
</div>;
}
return (
<div className="comment">
{clickableTitle}
</div>
);
}
});
ReactDOM.render(
<Comment />, document.getElementById('content')
);
코드의 주요 부분은 clickableTitle 변수입니다. 상태 변수 show 에 따라 Form 요소 또는 Button 요소가 될 수 있습니다. React는 구성 요소의 중첩을 허용합니다.
그래서 {renderableTitle} 요소를 렌더링 함수에 추가 할 수 있습니다. clickableTitle 변수를 찾습니다. 'this.state.show'값에 따라 해당 요소가 표시됩니다.
무국적 기능 구성 요소의 변형
const languages = [
'JavaScript',
'Python',
'Java',
'Elm',
'TypeScript',
'C#',
'F#'
]
// one liner
const Language = ({language}) => <li>{language}</li>
Language.propTypes = {
message: React.PropTypes.string.isRequired
}
/**
* If there are more than one line.
* Please notice that round brackets are optional here,
* However it's better to use them for readability
*/
const LanguagesList = ({languages}) => {
<ul>
{languages.map(language => <Language language={language} />)}
</ul>
}
LanguagesList.PropTypes = {
languages: React.PropTypes.array.isRequired
}
/**
* This syntax is used if there are more work beside just JSX presentation
* For instance some data manipulations needs to be done.
* Please notice that round brackets after return are required,
* Otherwise return will return nothing (undefined)
*/
const LanguageSection = ({header, languages}) => {
// do some work
const formattedLanguages = languages.map(language => language.toUpperCase())
return (
<fieldset>
<legend>{header}</legend>
<LanguagesList languages={formattedLanguages} />
</fieldset>
)
}
LanguageSection.PropTypes = {
header: React.PropTypes.string.isRequired,
languages: React.PropTypes.array.isRequired
}
ReactDOM.render(
<LanguageSection
header="Languages"
languages={languages} />,
document.getElementById('app')
)
여기 에서 그 실례를 찾을 수 있습니다.