در React، یک کامپوننت وقتی که state یا propهای مربوط به آن تغییر میکنند، مجددا رندر میشود. با توجه به این که state نمایانگر دادههای داخلی، و propها نمایانگر دادههای خارجی هستند، این اتفاق با عقل جور در میاید، اما همیشه موقعیت به این صورت نیست. برخی تکنیکها وجود دارند که از رندرهای غیر ضروری کامپوننت جلوگیری میکنند. بیایید برخی مثالهای موجود را بررسی کنیم.
همیشه مجددا رندر کنید
let count = 0;
class Button extends React.Component {
render = () => {
const { color } = this.props
count++;
return (
<React.Fragment>
<span> Render count: { count } </span>
<button style={{ color }}> text </button>
</React.Fragment>
)
}
}
class App extends React.Component {
state = {
color: 'red'
}
showRedButton = () => {
this.setState({
color: 'red'
})
}
showGreenButton = () => {
this.setState({
color: 'green'
})
}
render() {
const { color } = this.state;
const { showRedButton, showGreenButton } = this;
return (
<React.Fragment>
<Button color={color}/>
<button onClick={showRedButton}> red </button>
<button onClick={showGreenButton}> green </button>
</React.Fragment>)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
هر زمان که ما بر روی دکمهها (یا red و یا green) کلیک میکنیم، count افزایش مییابد، که نمایانگر رندر شدن مجدد کامپوننت Button است. گرچه، تنها prop که Button به آن وابستگی دارد، color است. اگر color همینطور به تغییر یافتن ادامه دهد، رندر مجدد غیر ضروری خواهد بود.
هدف: اگر ما همینطور دکمه red را فشار دهیم، میخواهیم که count بدون تغییر بماند؛ زیرا با توجه به این که color همانطور باقی میماند، ما نمیخواهیم کامپوننت Button را مجددا رندر کنیم.
تکنیک ۱: shouldComponentUpdate
let count = 0;
class Button extends React.Component {
shouldComponentUpdate(nextProps) {
if(this.props.color === nextProps.color) {
return false;
}
return true
}
render = () => {
const { color } = this.props
count++;
return (
<React.Fragment>
<span> Render count: { count } </span>
<button style={{ color }}> text </button>
</React.Fragment>
)
}
}
class App extends React.Component {
state = {
color: 'red'
}
showRedButton = () => {
this.setState({
color: 'red'
})
}
showGreenButton = () => {
this.setState({
color: 'green'
})
}
render() {
const { color } = this.state;
const { showRedButton, showGreenButton } = this;
return (
<React.Fragment>
<Button color={color}/>
<button onClick={showRedButton}> red </button>
<button onClick={showGreenButton}> green </button>
</React.Fragment>)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
نمونه کد shouldComponentUpdate
تکنیک ۲: React.PureComponenet
نحوه کار آن
let count = 0;
class Button extends React.PureComponent {
render = () => {
const { color } = this.props
count++;
return (
<React.Fragment>
<span> Render count: { count } </span>
<button style={{ color }}> text </button>
</React.Fragment>
)
}
}
class App extends React.Component {
state = {
color: 'red'
}
showRedButton = () => {
this.setState({
color: 'red'
})
}
showGreenButton = () => {
this.setState({
color: 'green'
})
}
render() {
const { color } = this.state;
const { showRedButton, showGreenButton } = this;
return (
<React.Fragment>
<Button color={color}/>
<button onClick={showRedButton}> red </button>
<button onClick={showGreenButton}> green </button>
</React.Fragment>)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
یک راه حل همه جانبه برای این مشکل
PureComponent اساسا همان Component است که هوک shouldComponentUpdate را به همراه دارد. پس آیا ما باید با توجه به این که PureComponent بهینهسازی رندر کردن بومی را در خود دارد، در هر صورت از آن استفاده کنیم؟ نه. PureComponent از برابری سطحی برای مقایسه propها و state استفاده میکند.
class TodoList extends React.PureComponent {
render() {
const { todos } = this.props;
return (<ul>
{
todos.map((it, index) => <li key={index}> {it} </li>)
}
</ul>)
}
}
class App extends React.Component {
inputRef = React.createRef()
state = {
todos: []
}
onAdd = () => {
let { todos } = this.state;
const text = this.inputRef.current.value;
todos.push(text);
this.setState({
todos
});
}
render() {
const { todos } = this.state;
const { onAdd, inputRef } = this
return (
<React.Fragment>
<input ref={inputRef} type='text' placeholder='enter todo'/>
<button onClick={onAdd}> add todo </button>
<TodoList todos={todos}/>
</React.Fragment>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
Anti PureComponenet
در مثال موجود، با توجه به این که todos (که مشابه به App است و به عنوان یک prop به TodoList منتقل شده است) همیشه ارجاع مشابه را دارد، TodoList هیچ وقت مجددا رندر نخواهد شد.
چگونه آن را به کار بیندازیم؟
class TodoList extends React.PureComponent {
render() {
const { todos } = this.props;
return (<ul>
{
todos.map((it, index) => <li key={index}> {it} </li>)
}
</ul>)
}
}
class App extends React.Component {
inputRef = React.createRef()
state = {
todos: []
}
onAdd = () => {
let { todos } = this.state;
const text = this.inputRef.current.value;
this.setState({
todos: [...todos, text]
});
}
render() {
const { todos } = this.state;
const { onAdd, inputRef } = this
return (
<React.Fragment>
<input ref={inputRef} type='text' placeholder='enter todo'/>
<button onClick={onAdd}> add todo </button>
<TodoList todos={todos}/>
</React.Fragment>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
ارجاع PureComponent
حال که هر زمان ما setState را فراخوانی میکنیم، یک آرایه todos جدید میسازیم، این کد به درستی کار میکند.
React.memo - برای کامپوننت تابعی
نحوه کار آن
let count = 0;
const Button = React.memo(function(props) {
const { color } = props
count++;
return (
<React.Fragment>
<span> Render count: { count } </span>
<button style={{ color }}> text </button>
</React.Fragment>
)
})
class App extends React.Component {
state = {
color: 'red'
}
showRedButton = () => {
this.setState({
color: 'red'
})
}
showGreenButton = () => {
this.setState({
color: 'green'
})
}
render() {
const { color } = this.state;
const { showRedButton, showGreenButton } = this;
return (
<React.Fragment>
<Button color={color}/>
<button onClick={showRedButton}> red </button>
<button onClick={showGreenButton}> green </button>
</React.Fragment>)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید