React.js study repository ๐
- react library
- react-filepond : file upload library
usage
import { FilePond, registerPlugin } from "react-filepond"
import FilePondPluginImageExifOrientation from "filepond-plugin-image-exif-orientation"
import FilePondPluginImagePreview from "filepond-plugin-image-preview"
import 'filepond/dist/filepond.min.css'
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css'
:
render() {
return (
<div className="App">
{/* Pass FilePond properties as attributes */}
<FilePond
ref={ref => (this.pond = ref)}
files={this.state.files}
allowMultiple={true}
maxFiles={3}
server="/api"
oninit={() => this.handleInit()}
onupdatefiles={fileItems => {
// Set currently active file objects to this.state
this.setState({
files: fileItems.map(fileItem => fileItem.file)
});
}}
/>
</div>
);
}
usage
import React, { Component } from 'react';
import { Editor } from 'react-draft-wysiwyg';
<Editor
wrapperClassName="wrapper-class"
editorClassName="editor-class"
toolbarClassName="toolbar-class"
wrapperStyle={<wrapperStyleObject>}
editorStyle={<editorStyleObject>}
toolbarStyle={<toolbarStyleObject>}
/>
usage
<MaskedInput
mask={['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]}
className="form-control"
placeholder="Enter a phone number"
// you can input value
value={this.state.number}
guide={false}
id="my-input-id"
onBlur={() => {}}
onChange={() => {}}
/>
like Vue.js class style binding
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'
// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
- render() ํจ์ ์คํ ์ฌ๋ถ๋ฅผ ๊ฐ๋ฐ์๊ฐ ๊ฒฐ์ ํ ์ ์์. ๋ถํ์ํ ๋ ๋๋ง์ ๋ง์ ์ ์์.
import React, { Component } from 'react';
class TOC extends Component {
shouldComponentUpdate (newProps, newState) {
// ๋ฐ๋ state์ state์ ๊ฐ์ ๋ฐ์ ์ ์์
if (this.props.data === newProps.data) {
return false;
}
return true;
}
}
props๋ก ๋ฐ์ ๋ด์ฉ์ ์์ ํ ๋๋, setState()๋ก ์์ ํด์ผํ๋ค.
<header>
<h1><a href="/" onClick={function(e) {
this.setState({ mode: 'welcome' });
}.bind(this)}>{ this.state.subject.title }</a>
</h1>
</header>
shouldComponentUpdate()ํจ์๋ฅผ ์ฌ์ฉํ๋ค๋ฉด concat, Array.from()๊ณผ ๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํด์ ์๋ณธ์ ๋ฐ๊พธ์ง ์๋๋ค.
- arr copy : Array.from()
- object copy : Object.assign()
var a = {name: 'tonz'};
var b = Object.assign({}, a); // {name: 'tonz'}
var c = Object.assign({left: 1, right: 2}, a); // {left: 1, right: 2, name: 'tonz'}
render ํจ์์ ๋ฆฌํด ๊ฐ์ ํญ์ ์ต์์ ํ๊ทธ๋ถํฐ ์์ํด์ผํ๋ค.
import React, { Component } extends from 'react';
class Subject extends Component {
render () {
return (
<header>
<h1>WEB</h1>
world wide web!
</header>
);
}
}
class App extends Component {
render () {
return (
<div classNAme="App">
<Subject></Subject>
</div>
);
}
}
export default App;
- Subject.js
๋ด๋ถ์์ this.props๋ก ์ ๊ทผํ๋ค.
class Subject extends Component {
render () {
return (
<header>
<h1>{ this.props.title }</h1>
{ this.props.sub }
</header>
);
}
}
- App.js
class App extends Component {
render () {
return (
<div classNAme="App">
<Subject title="WEB" sub="world wide web!"></Subject>
</div>
);
}
}
src
-components
-Subject.js
:
-App.js
- Subject.js
impornt & export
import React, { Component } extends from 'react';
class Subject extends Component {
render () {
return (
<header>
<h1>{ this.props.title }</h1>
{ this.props.sub }
</header>
);
}
}
export default Subject;
- App.js
import Subject from './Components/Subject'
class App extends Component {
render () {
return (
<div classNAme="App">
<Subject title="WEB" sub="world wide web!"></Subject>
</div>
);
}
}
- constructure()
์ปดํฌ๋ํธ๊ฐ ์คํ๋ ๋, ๊ฐ์ฅ ๋จผ์ ์คํ๋๋ฉฐ ์ด๊ธฐํ๋ฅผ ๋ด๋นํ๋ค. ์์ ์ปดํฌ๋ํธ ๊ฐ์ ํ์ ์ปดํฌ๋ํธ๋ก ์ ๋ฌํ๊ณ ์ถ์ ๋, state๋ฅผ ์ด์ฉ.
import Subject from './Components/Subject'
class App extends Component {
constructure (props) {
super(props);
this.state = {
subject: {title: 'WEB', sub: 'world wide web!'}
}
}
render () {
return (
<div classNAme="App">
<Subject
title={this.state.subject.title}
sub={this.state.subject.sub}>
</Subject>
</div>
);
}
}
state ๊ฐ์ด ๊ฐฑ์ ๋๋ฉด render()๊ฐ ์คํ๋๋ฉฐ, ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง update๋๋ค.
class Clock extends Component {
constructure (props) {
super(props);
this.launchClock
this.state = {
// ์ด๊ธฐ ์ํ์ ํ์ฌ ์๊ฐ ์ถ๊ฐ
currentTime: (newDate()).toLocaleString('en')
}
}
launchClock () {
setInterval(() => {
this.setState({
// ๋งค ์ด๋ง๋ค ํ์ฌ์๊ฐ์ผ๋ก ์ํ ๊ฐฑ์
currentTime: (newDate()).toLocaleString('en')
});
}, 1000);
}
render () {
return (
<div>
{ this.state.currentTime }
</div>
);
}
}
- key
TOC ์ปดํฌ๋ํธ์์ data[i] ๋ฑ์ ๋ฐฉ์์ผ๋ก ์ ๊ทผ ๊ฐ๋ฅํจ. ๊ฐ ๋ฐฐ์ด์ ์์๋ key๋ก ๊ตฌ๋ถํ๋ฉด๋จ. vue์ v-for์ key๊ฐ๊ณผ ๋์ผ.
class App extends Component {
constructure (props) {
super(props);
this.state = {
subject: {title: 'WEB', sub: 'world wide web!'},
contents: [
{id: 1, title: 'HTML', desc: 'HTML is HyperText...'}
{id: 2, title: 'CSS', desc: 'CSS is for design'}
{id: 3, title: 'JS', desc: 'JS JS JS'}
]
}
}
render () {
return (
<div classNAme="App">
<Subject
title={this.state.subject.title}
sub={this.state.subject.sub}>
</Subject>
<TOC data={this.state.contents}></TOC>
</div>
);
}
}
- if/else statement in JSX
render () {
let sessionFlag = this.props.user.session // bull
return (
<div>
<a href={(sessionFlag) ? '/logout' : '/login'}>
{(sessionFlag) ? 'Logout' : 'Login'}
</a>
</div>
)
}
๋ค์์ ํ๋ฆฐ ๊ตฌ๋ฌธ์ด๋ค. ์ค๊ดํธ ๋ด์์ return๋ฌธ์ ์ฌ์ฉํ์ง ์๋๋ค. ์ผํญ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ค.
class={if(!this.props.admin) return 'hide'}
- JSX is converted to javascipt
- data-์์ฑ
์ฌ์ฉ์ ์ ์ ์์ฑ์ ์ด์ฉํ ๋, data- prefix๋ฅผ ๋ถํ์ง ์์ผ๋ฉด React์์๋ ๋ ๋๋ง๋์ง ์๋๋ค. HTML ํ์ค ์์ฑ์ด ์๋๊ธฐ ๋๋ฎจ.
// rendering OK in React
<li data-object-id="321"></li>
// not rendering in React
<li object-id="321"></li>
- style
๋ฌธ์์ด ๋์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๋ค. css๋ ์นด๋ฉ์ผ์ด์ค ํ๊ธฐ
let smallFontSize = {fontSize: '10px'}
<input style={smallFontSize}>
- class & for
React์ JSX๋ class, for๋ฅผ ์ ์ธํ๋ฉด ํ์ค HTML ์์ฑ์ ๋ชจ๋ ์ฌ์ฉํ ์ ์๋ค.
<div className="hidden">...</div>
:
<label htmlFor={this.props.name}>
{this.props.label}
</label>
:
- Boolean ๊ฐ์ ์์ฑ ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
disabled, required, checked, autofocus, readOnly์ ๊ฐ์ ์ผ๋ถ ์์ฑ์ ํผ ์์์๋ง ์ฌ์ฉํ๋ค. ์์ฑ ๊ฐ์ ๋ฐ๋์ {} ์์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ผ๋ก ์์ฑํด์ผ ํ๋ค.
// GOOD
<input disabled={false} />
// XXX !!!!
<input disabled="false" />
7) Redux
1) React ์ปดํฌ๋ํธ ๋ง๋ค๊ธฐ: ํ์ React ์ปดํฌ๋ํธ๋ก prop(or state)์ dispatch() ๋ฉ์๋๋ฅผ ์ ๋ฌํ๋ค.
const todolistStateToProps = (state) => {
return {
todos: state.todos
}
}
const todolistDispatchToProps = (dispatch) => {
return {
onClick(data){
dispatch(complete(data))
}
}
}
// connect์ ์ฒซ๋ฒ์งธ parameter๋ state, ๋๋ฒ์งธ parameter๋ dispatch ํจ์
export default connect(todolistStateToProps,todolistDispatchToProps)(TODOList);
2) ์ก์ ๋ช ๋ น์ด์ ์ก์ ๋ฉ์๋ ๋ง๋ค๊ธฐ: state ๋ณ๊ฒฝ๊ณผ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ๋ค.
function complete({complete, id}) {
return { type: COMPLETE_TODO, complete, id};
}
function complete2(data2) {
return (dispatch) => {
return fetch("api/add.json").then(
res => res.json().then(data => dispatch(complete(data2)))
);
};
}
3) ๋ฆฌ๋์ ์์ฑ: ์คํ ์ด์ ๊ตฌ์กฐ๋ฅผ ์ ํ๋ค.
const todos = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
return [
...state, todo(undefined, action)
];
case COMPLETE_TODO:
return state.map(t => todo(t, action));
default:
return state;
}
}
4) dispatch() ๋ฉ์๋์ ์ก์ ๊ฒฐ๊ณผ ์ ๋ฌ: ์ก์ ์ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ฌํ๋ค.
ex) Redux์ ์ดํด
- store
ํ ๊ฐ์ ๊ณ์ธตํ ๊ฐ์ฒด. ์ ํ๋ฆฌ์ผ์ด์ ์ state๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
- React Component
stae์ ๋ง๊ฒ ํ๋ฉด์ ๊ทธ๋ฆฐ๋ค.
- action creator
์ฌ์ฉ์๊ฐ ๋ฐ์์ํค๋ ์ด๋ฒคํธ์ ๋ง์ถฐ ์คํ ์ด์ ์ ๋ฌํ ์ก์ ์ ๋ง๋ ๋ค. ์ก์ ์์ฑ์๊ฐ ๋ง๋๋ ์ก์ ์ [์์๊ฐ์ฒด]๋ค.
- reducer
ํ์ฌ state์ ์ก์ ์ ์ ๋ฌ๋ฐ์ ์๋ก์ด state๋ฅผ ๋ฐํํ๋ค. ๋ฆฌ๋์๋ [์์ ํจ์]๋ค.
8) props-type
class DatePicker extends Component {
:
}
:
DatePicker.propTypes {
currentDate: PropTypes.string.isRequired,
rows: PropTypes.number,
// ์ด๊ฑฐํ(enum)์ผ๋ก ์ฒ๋ฆฌํ์ฌ prop๊ฐ ํน์ ๊ฐ๋ค๋ก ์ ํ๋๋๋ก ํ ์ ์์ต๋๋ค.
locale: PropTypes.oneOf(['US', 'KO']),
}
์ฝ๋ ์ฌ์ฌ์ฉ์ ์ํ React ๊ณ ์ฐจ ์ปดํฌ๋ํธ
const LoadWebSite = (Component) => {
:
class _LoadWebSite extends Component {
:
_LoadWebSite.displayName = 'Enhanced Component'
return _LoadWebSite
}
}
- ํ๋ ์ ํ ์ด์ ์ปดํฌ๋ํธ
DOM๊ณผ ์คํ์ผ์ ๊ตฌ์กฐ๋ง ์ถ๊ฐํ๋ค. ์์ฑ(props)๋ ์ฌ์ฉํ์ง๋ง ์ํ(state)๋ฅผ ๊ฐ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์๋ค.
- defaultChecked๋ initail render์๋ง call๋๋ฏ๋ก update๊ฐ ํ์ํ๋ฉด checked๋ฅผ ์ฌ์ฉํด์ผํ๋ค.
<input type="checkbox"
name="tomato"
checked={ this.state.input === 1 }
// value๊ฐ์ state๊ฐ์ด ์๋ ์ง์ ๊ฐ์ผ๋ก setting๊ฐ๋ฅ
value={ 1 }
innerRef={ (input) => this.tomatoInput = input }
onChange={ this.selectInput }
disabled={ isInputDisabled } /> TOMATO
:
selectInput (e) {
let { value } = e.target
var inputValue = Number(value)
this.setState({ input: inputValue })
}