syntax extension to JavaScript
자바스크립트안에서 HTML 문법을 사용해 view를 구성할 수 있게 도와주는 문법
may look like a template language, but comes with the full power of JS.
produces React "elements". Can render them to the DOM.
helpful as a visual aid when working with UI inside the JS code (React)
React separates concerns(technologies) with loosely coupled units called "components" that contain both markup and logic.
Can put any valid JS expression inside the curly braces
```js
function formatName(user) { const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
```
Wrapping it in parentheses avoid automatic semicolon insertion.JSX expressions become regular JS function calls and evaluate to JS objects.
```js
function getGreeting(user) { ```
Can use quotes to specify string literals as attributes
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;
- JSX is closer to JS than to HTML. React DOM uses camelCase property naming convention.
If a tag is empty, it can be closed immediately with />, like XML
const element = <img src={user.avatarUrl}/>
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
- JSX prevents **Injection attack (XSS : cross-site-scripting)** because React DOM escapes any values embedded in JSX before rendering. Everything is converted to string beforehand.
- Babel compiles JSX down to **React.createElement()** calls. Makes "React elements" and React reads these objects and use them to construct the DOM up to date.
```js
const element - (
<h1 className = "greeting">
Hello, world!
</h1>
);
//this is same as =>
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
)
**Output**:
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
const element = <h1>Hello, world</h1>
```js
const element = <h1>Hello, world</h1>
ReactDOM.render(element, document.getElementById('root')); ```
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Above is an example of a valid React component. It accepts a single "props"(properties) object argument with data and returns a React element. Such components are called "function components".
Below is an example of a ES6 class component.
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
const element = <Welcome name = "Sara" />;
When React sees an element represent user-defined component, it passes JSX attributes to this component as a single object. "Props"
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
//
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
Always start component names with a capital letter
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
The component above constantly updates the time through setInterval. What we want now is to make the Clock component(shows time and updates on its own) reusuable and encapsulated.
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
Now, the Clock component is encapsulated. But, it cannot set up a timer and update the UI every second. To do this, "state" needs to be added to the Clock component. Private and fully controlled by the component.
ES6 Version
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Clock is now defined as a class. render method will be called each time an update happens, but if we render into the same DOM node, only one version of Clock class will be used. Local state and lifecycle methods
Use this.state and constructor to create an instance then add local state to a Class
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
setState()
- Do not modify state directly.
```js
//wrong
this.state.comment = "Hi";
//correct
this.setState({comment: "Hi"});
```
this.state will only appear in the constructor.
- State Updates may be Asynchronous
- React may batch multiple setState() calls. this.props and this.state may be updated asynchronously.
```js
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
```
- State Updates are Merged
- When setState() is called, object provided is merged into the current state. However, independent variables can be updated independently with separate setState() calls.
```js
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
//Two functions each udpates posts and comments.
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
```
The Data Flows Down
- Neither parent nor chiildren components can know the state status of other components. State is often called local or encapsulated.
//HTML
<button onclick="activateLasers()">
Activate Lasers
</button>
//React
<button onClick={activateLasers}>
Activate Lasers
</button>
```js
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row```
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
배열에서 map을 통해 li 엘리먼트를 첨부해주고 ul에 렌더 해준다. 이 process를 함수로 만든 후 렌더해주는 첫번쩨 인자로 넣어 줄 수도 있다.
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
하지만 이 함수는 key가 없어서 리스트에 키를 포함해 줘야 한다고 나온다. 키는 special string sttribute로 리액트가 무슨 아이템이 변하거나, 추가되었거나, 제거되었는지 알아차리는데 도움을 준다.
키는 보통 그 아이템을 구분할때 바로 알아차릴 수 있는 string으로 사용한다. 없으면 index를 최후의 수단으로 사용해야 한다.
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
//고정 아이디가 없을 경우
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
아이템의 순서가 바뀔수도 있어서 인덱스 값을 키로 설정하는 것은 권장하지 않는다. 만약 list의 아이템에 특정 키를 지정하지 않는다면 리액트는 자동으로 인덱스를 키 로 사용한다.
<input type = "file" />