필요할 때만 Render 한다.
Reconciliation
- Render 전후의 일치 여부를 판단하는 규칙
- 서로 다른 타입의 두 Element 는 서로 다른 트리를 만들어낸다.
- 개발자가 key prop 을 통해, 여러 Rendering 사이에서 어떤 자식 Element 가 변경되지 않아야 할 지 표시해 줄수 있다.
// App.js
import logo from './logo.svg';
import './App.css';
import React from 'react';
class Foo extends React.Component {
componentDidMount() {
console.log("Foo componentDidMount");
}
componentWillUnmount() {
console.log("Foo componentWillUnmount");
}
static getDerivedStateFromProps(nextProps, prevProps) {
console.log("Foo getDrivedStateFromProps", nextProps, prevProps);
return {};
}
render(){
console.log("Foo render");
return (
<p>Foo</p>
);
}
}
class App extends React.Component {
state = {
count: 0
};
componentDidMount() {
setInterval(() => {
this.setState({count: this.state.count + 1});
}, 1000);
}
render() {
if(this.state.count % 2 === 0) {
return (
// <div className='before' title='stuff' />
// <div style={{color: 'red', fontWeight: 'bold'}} />
<Foo name="Mark" />
);
}
return (
// <div className='after' title='stuff' />
// <div style={{color: 'green', fontWeight: 'bold'}} />
<Foo name= "Jane" />
);
}
}
export default App;
// App.js
// key props
import logo from './logo.svg';
import './App.css';
import React from 'react';
class Foo extends React.Component {
componentDidMount() {
console.log("Foo componentDidMount", this.props.children);
}
componentWillUnmount() {
console.log("Foo componentWillUnmount");
}
static getDerivedStateFromProps(nextProps, prevProps) {
console.log("Foo getDrivedStateFromProps", nextProps, prevProps);
return {};
}
render(){
console.log("Foo render", this.props.children);
return (
<p>Foo</p>
);
}
}
class App extends React.Component {
state = {
count: 0
};
componentDidMount() {
setInterval(() => {
this.setState({count: this.state.count + 1});
}, 1000);
}
render() {
if(this.state.count % 2 === 0) {
return (
<ul>
{/* <Foo>First</Foo>
<Foo>Second</Foo> */}
<Foo key="2">Second</Foo>
<Foo key="3">Third</Foo>
</ul>
);
}
return (
<ul>
<Foo key="1">First</Foo>
<Foo key="2">Second</Foo>
<Foo ket="3">Third</Foo>
</ul>
);
}
}
export default App;
// App.js
// shouldComponentUpdate
// PureComponent
import logo from './logo.svg';
import './App.css';
import React from 'react';
class Person extends React.Component.PureComponent {
// PureComponent 도 바뀐 부분이 없으면 렌더하지 않음!
// 바뀐 부분이 없으면 렌더하지 않는다!
// shouldComponentUpdate(previousProps){
// for(const key in this.props){
// if(previousProps[key] !== this.props[key]){
// return true;
// }
// return false;
// }
// }
render(){
console.log("Person render");
const {name, age} = this.props
return (
<div>
{name} / {age}
</div>
);
}
}
class App extends React.Component {
state = {
text: "",
persons: [
{id: 1, name: "Mark", age: 39},
{id: 2, name: "Jane", age: 28}
]
};
render() {
const { text, persons } = this.state;
return (
<div>
<input type= "text" value={text} onChange={this._change} />
<ul>{persons.map(person => {
return <Person {...person} key={person.id} />
})}</ul>
</div>
);
}
_change = e => {
this.setState({
...this.state,
text: e.target.value
});
}
}
export default App;
// App.js
// function 으로 사용할 때, React.memo 를 사용하면 바뀐 부분이 없으면 랜더하지 않음
const Person = React.memo(({name, age}) => {
console.log("Person render");
return (
<div>
{name} / {age}
</div>
);
});
// App.js
// React.memo
// useCallback
import logo from './logo.svg';
import './App.css';
import React, { useState } from 'react';
// function 으로 사용할 때, React.memo 를 사용하면 바뀐 부분이 없으면 랜더하지 않음
const Person = React.memo(({name, age}) => {
console.log("Person render");
return (
<div>
{name} / {age}
</div>
);
});
function App() {
const [state, setState] = useState({
text: "",
persons: [
{id: 1, name: "Mark", age: 39},
{id: 2, name: "Jane", age: 28}
]
});
const toPersonClick = React.useCallback(() => {}, []);
const { text, persons } = state;
return (
<div>
<input type= "text" value={text} onChange={change} />
<ul>
{persons.map(person => {
return <Person {...person} key={person.id} onClick={toPersonClick} />
})}
</ul>
</div>
);
};
function change(e) {
setState({
...state,
text: e.target.value
});
};
export default App;
Portals
부모 Component 의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 Rendering 하는 최고의 방법을 제공함
<!-- public/index.html -->
<div id="modal"></div>
/* src/index.css */
#modal {
position: absolute;
top: 0;
left: 0;
}
// src/components/Modal.jsx
import ReactDOM from 'react-dom';
const Modal = ({children}) =>
ReactDOM.createPortal(children, document.querySelector('#modal'));
export default Modal;
// App.js
function App () {
const [visible, setVisible] = useState(false);
const open = () => {
setVisible(true)
};
const close = () => {
setVisible(false)
};
return (
<div>
<button onClick={open}>Open</button>
{visible && (
<Modal>
<div style={{
width: '100vw',
height: '100vh',
background: 'rgba(0, 0, 0, 0.5)'
}}
onClick={close}
>
Hello
</div>
</Modal>
)}
</div>
);
}
// src/component/MyInput.jsx
import React from "react";
export default React.forwardRef(function MyInput (props, ref) {
return (
<div>
<p>MyInput</p>
<input ref={ref} />
</div>
);
});
// App.js
function App () {
const myInputRef= useRef();
const click = () => {
console.log(myInputRef.current.value);
};
return (
<div>
<MyInput ref={myInputRef} />
<button onClick={click}>send</button>
</div>
);
}