State និង Lifecycle
ទំព័រនេះបង្ហាញពីគំនិតនៃ state និង lifecycle នៅក្នុង React component. អ្នកអាចរកឃើញ លំអិត API component លំអិតនៅទីនេះ.
សូមពិចារណាគំរូនាឡិកាពី ផ្នែកមួយនៃផ្នែកមុន. នៅក្នុង ការបង្ហាញធាតុ,យើងទើបតែរៀនវិធីដើម្បីធ្វើបច្ចុប្បន្នភាព UI តែមួយប៉ុណ្ណោះ. យើងហៅ ReactDOM.render()
ដើម្បីផ្លាស់ប្តូរលទ្ធផលបង្ហាញ:
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);
នៅក្នុងផ្នែកនេះ យើងនឹងរៀនពីរបៀបបង្កើត component Clock
ដែលអាចប្រើឡើងវិញបាន និង encapsulated. វានឹងបង្កើតកម្មវិធីកំណត់ពេលវេលាផ្ទាល់ខ្លួនរបស់វាហើយធ្វើបច្ចុប្បន្នភាពរៀងរាល់វិនាទី។
យើងអាចចាប់ផ្ដើមដោយ encapsulating របៀបមើលនាឡិកា:
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);
ទោះយ៉ាងណា, វានឹកនូវតម្រូវការដ៏សំខាន់មួយ:ការពិតដែលថា Clock
កំណត់កម្មវិធីកំណត់ពេលវេលាមួយនិងធ្វើបច្ចុប្បន្នភាព UI ជារៀងរាល់វិនាទីគួរតែជាការអនុវត្ដន៍លម្អិតនៃ Clock
.
ជាគំនិត យើងចង់សរសេរវាម្តងនិងមានការធ្វើឱ្យទាន់សម័យ ‘Clock’ ខ្លួនវាផ្ទាល់:
ReactDOM.render(
<Clock />, document.getElementById('root')
);
ដើម្បីអនុវត្ត យើងត្រូវបន្ថែម “state” ទៅcomponent Clock
។
State គឺស្រដៀងទៅនឹង props ប៉ុន្តែវាមានលក្ខណៈឯកជនហើយត្រូវបានគ្រប់គ្រងយ៉ាងពេញលេញដោយ component។
យើង បានរៀបរាប់ពីមុន components ដែលបានកំណត់ជា classes មានលក្ខណៈពិសេសបន្ថែមមួយចំនួន. Local state គឺពិតប្រាកដណាស់: អាចប្រើបានតែចំពោះ classes.
បម្លែង Function ទៅ Class
អ្នកអាចបម្លែង function component ដូច Clock
ទៅ class ក្នុងប្រាំជំហាន:
- បង្កើត ES6 class, ជាមួយឈ្មោះដូចគ្នា, នោះ extends
React.Component
. - បន្ថែមវិធីសាស្ត្រទទេមួយទៅវា
render()
. - ផ្លាស់ទីនៃតួ function ចូលទៅក្នុង
render()
. - ជំនួស
props
ជាមួយthis.props
ក្នុងrender()
body. - លុបការប្រកាស function ទទេដែលនៅសល់។
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Clock
ឥឡូវត្រូវបានកំណត់ជា class ជាជាង function។
វិធីសាស្ត្រ render
នឹងត្រូវបានហៅរាល់ពេលដែលការធ្វើបច្ចុប្បន្នភាពកើតឡើង, ប៉ុន្តែដរាបណាយើងបង្ហាញ <Clock />
ចូលទៅក្នុង DOM node ដូចគ្នា, មានតែវត្ថុតែមួយនៃ Clock
class នឹងត្រូវបានប្រើ. នេះអនុញ្ញាតឱ្យយើងប្រើលក្ខណៈពិសេសបន្ថែមដូចជា local state និង lifecycle methods។
បន្ថែម Local State ទៅ Class
យើងនឹងផ្លាស់ទី date
ពី props ទៅ state ក្នុងបីជំហាន:
- ជំនួស
this.props.date
ជាមួយthis.state.date
ក្នុងrender()
:
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>
);
}
}
- បន្ថែម class constructor ដែលកំណត់ដំបូង
this.state
:
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>
);
}
}
ចំណាំពីរបៀបដែលយើងហុច props
ទៅ constructor:
constructor(props) {
super(props); this.state = {date: new Date()};
}
Class components គួរតែហៅ constructor ជាមួយ props
.
- យក
date
ចេញពីធាតុ<Clock />
:
ReactDOM.render(
<Clock />, document.getElementById('root')
);
ក្រោយមកយើងនឹងបន្ថែមកូដកំណត់ពេលវេលាទៅ component ខ្លួនឯងវិញ។
លទ្ធផលមើលទៅដូចនេះ:
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')
);
បន្ទាប់មក យើងនឹងបង្កើត Clock
បង្កើតដោយផ្ទាល់ខ្លួនរបស់វាហើយធ្វើបច្ចុប្បន្នភាពរៀងរាល់វិនាទី។
បន្ថែម វិធីសាស្រ្ត Lifecycle ទៅ Class
នៅក្នុងកម្មវិធីដែលមាន components ជាច្រើន វាមានសារៈសំខាន់ខ្លាំងណាស់ក្នុងការធ្វើអោយមានភាពទំនេរ នៅពេលដែល components បានប្រើប្រាស់ត្រូវបានបំផ្លាញ។
យើងចង់ ធ្វើការកំណត់ពេល(timer) នៅពេលណាដែល Clock
ត្រូវបានបង្ហាញទៅ DOM ជាលើកដំបូង. នេះត្រូវបានគេហៅ “mounting” នៅ React.
យើងក៏ចង់ ជម្រះការកំណត់ម៉ោង(timer) នៅពេលណាដែល DOM ដែលបានផលិតដោយClock
បានយកចេញ. នេះត្រូវបានគេហៅ “unmounting” នៅ React.
យើងអាចប្រកាសវិធីសាស្រ្តពិសេសនៅលើ component class ដើម្បីដំណើរការកូដមួយចំនួននៅពេលណា component mounts និង unmounts:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() { }
componentWillUnmount() { }
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
វិធីសាស្រ្តទាំងនេះត្រូវបានហៅ “lifecycle methods”.
componentDidMount()
ដំណើរការបន្ទាប់ពីទិន្នផលcomponentត្រូវបានបង្ហាញទៅ DOM។ នេះគឺជាទីកន្លែងល្អដើម្បីធ្វើការកំណត់ពេល(timer):
componentDidMount() {
this.timerID = setInterval( () => this.tick(), 1000 ); }
ចំណាំ របៀបដែលយើងរក្សាទុក timer ID អោយបានត្រឹមត្រូវលើ this
(this.timerID
)។
ខណៈពេល this.props
ត្រូវបានបង្កើតឡើងដោយ React ខ្លួនឯង និង this.state
មានអត្ថន័យពិសេស, អ្នកមានសិទ្ធិបន្ថែម fields ទៅ class ដោយខ្លួនឯង ប្រសិនបើអ្នកត្រូវការរក្សាទុកអ្វីមួយដែលមិនចូលរួមនៅក្នុង data flow (ដូចជា timer ID).
យើងនឹងលុបចេញនូវកម្មវិធីកំណត់ម៉ោងក្នុង componentWillUnmount()
lifecycle method:
componentWillUnmount() {
clearInterval(this.timerID); }
ទីបំផុត យើងនឹងអនុវត្តវិធីសាស្ត្រមួយដែលហៅថា tick()
ដែលថា Clock
component នឹងដំណើរការរាល់វិនាទី។
វានឹងប្រើ this.setState()
ដើម្បីកំណត់ពេលធ្វើឱ្យទាន់សម័យទៅ component local state៖
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')
);
ឥឡូវនេះនាឡិកាដំណើរការរាល់វិនាទី។
តោះសង្ខេបឡើងវិញ អ្វីដែលកើតឡើងនិងលំដាប់ដែលវិធីសាស្រ្តត្រូវបានគេហៅថា:
- ពេលណា
<Clock />
ត្រូវបានបញ្ជូនទៅReactDOM.render()
, React ហៅ constructor នៃClock
component. ចាប់តាំងពីClock
ត្រូវការបង្ហាញពេលវេលាបច្ចុប្បន្ន, វាចាប់ផ្ដើមthis.state
ជាមួយ object រួមទាំងពេលបច្ចុប្បន្ន។ ក្រោយមកយើងនឹងធ្វើបច្ចុប្បន្នភាព state។ - React បន្ទាប់មកហៅ
Clock
component’srender()
method. នេះគឺជារបៀបដែល React រៀនអ្វីដែលគួរត្រូវបានបង្ហាញនៅលើអេក្រង់។ React បន្ទាប់មកធ្វើឱ្យទាន់សម័យ DOM ដើម្បីផ្គូផ្គងទៅការបង្ហាញរបស់Clock
។ - នៅពេលដែល
Clock
លទ្ធផលត្រូវបានបញ្ចូលក្នុង DOM, React ហៅទៅcomponentDidMount()
lifecycle method. នៅខាងក្នុង,Clock
សួរកម្មវិធីរុករកដើម្បីបង្កើតកម្មវិធីកំណត់ពេលវេលា ដែលអាចធ្វើការហៅទៅtick()
method ម្តងក្នុងមួយវិនាទី។ - រៀងរាល់វិនាទី កម្មវិធីរុករក ធ្វើការហៅទៅកាន់
tick()
method. នៅខាងក្នុង, theClock
component កំណត់ពេលវេលាធ្វើបច្ចុប្បន្នភាព UI តាមការហៅsetState()
ជាមួយ object ដែលមានពេលបច្ចុប្បន្ន. សូមអរគុណដល់ការហៅទៅកាន់setState()
, React ដឹងថា state បានផ្លាស់ប្តូរ, ហើយធ្វើការហៅទៅកាន់render()
method ជាថ្មីម្តងទៀតដើម្បសិក្សាថាអ្វីដែលគួរនៅលើអេក្រង់. ពេលនេះ,this.state.date
ក្នុងrender()
method នឹងខុសគ្នា, ដូច្នេះការបង្ហាញទិន្នផលនឹងរួមបញ្ចូលពេលវេលាដែលបានធ្វើឱ្យទាន់សម័យ។ React ធ្វើបច្ចុប្បន្នភាពតាម DOM។ - ប្រសិនបើ
Clock
component ត្រូវបានយកចេញពី DOM, React ហៅទៅកាន់componentWillUnmount()
lifecycle method ដូច្នេះកម្មវិធីកំណត់ពេលវេលាត្រូវបានបញ្ឈប់។
ការប្រើប្រាស់ State ឲបានត្រឹមត្រូវ
មានរឿងបីដែលអ្នកគួរដឹងពី setState()
.
កុំកែប្រែ State ដោយផ្ទាល់
ឧទាហរណ៍, នេះនឹងមិន re-render a component:
// Wrong
this.state.comment = 'Hello';
ជំនួសដោយ, ការប្រើ setState()
:
// Correct
this.setState({comment: 'Hello'});
ជាកន្លែងតែមួយគត់ដែលអ្នកអាចចាត់តាំង(assign) this.state
គឺជា constructor.
ការបន្ទាន់សម័យរបស់ State អាចជា Asynchronous
React អាចមានច្រើន batch setState()
ហៅចូលទៅក្នុងការធ្វើបច្ចុប្បន្នភាពតែមួយសម្រាប់ performance។
ពីព្រោះ this.props
និង this.state
អាចត្រូវបានធ្វើបច្ចុប្បន្នភាព asynchronously,អ្នកមិនគួរពឹងផ្អែកលើតម្លៃរបស់វាសម្រាប់ការគណនាបន្ទាប់ពី state នោះទេ។
ឧទាហរណ៍, code នេះ អាចបរាជ័យក្នុងការធ្វើបច្ចុប្បន្នភាពនៃ counter:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
ដើម្បីធ្វើការកែតម្រូវ, ប្រើសំណុំបែបបទទីពីរនៃ setState()
ដែលទទួលយក function ជាជាងមួយ object. function នោះ នឹងទទួលបាន state ពីមុនជាតម្លៃដំបូង និង props នៅពេលដែលការ update ត្រូវបានអនុវត្តជាតម្លៃបន្ទាប់:
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
យើងបានប្រើ arrow function ខាងលើ, ប៉ុន្តែវាក៏ធ្វើការជាមួយ regular functions ផងដែរ:
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
ការបន្ទាន់សម័យ State ត្រូវបានបញ្ចូលគ្នា
នៅពេលអ្នកហៅ setState()
, React ធ្វើការបញ្ចូល object ដែលអ្នកបានផ្តល់ជូននៅក្នុង state បច្ចុប្បន្ន។
ឧទាហរណ៍, state របស់អ្នក អាចមានអថេរ(variables) ឯករាជ្យជាច្រើន:
constructor(props) {
super(props);
this.state = {
posts: [], comments: [] };
}
បន្ទាប់មកអ្នកអាចធ្វើការ update ពួកវាដាច់ដោយឡែកពីគ្នា setState()
ដោយការហៅ:
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts });
});
fetchComments().then(response => {
this.setState({
comments: response.comments });
});
}
ការរួមបញ្ចូលគ្នាគឺ shallow, ដូច្នេះ this.setState({comments})
leaves this.state.posts
intact, ប៉ុន្តែជំនួសទាំងស្រុងដោយ this.state.comments
.
ទិន្នន័យ Flows Down
ទាំងparentនិង child components មិនអាចដឹងថាវាមាន component ជាក់លាក់មួយគឺ stateful or stateless, ហើយពួកគេមិនគួរខ្វល់ថា តើវាត្រូវបានគេកំណត់ថាជា function ឬ a class នោះទេ.
នេះជាមូលហេតុដែល state គឺជាញឹកញាប់ហៅ local ឬ encapsulated។ វាមិនអាចប្រើបាន វាមិនអាចចូលទៅដល់ component ណាមួយក្រៅពី object ដែលមាននិងកំណត់ដោយខ្លួនវាទេ។
Component អាចជ្រើសរើសដើម្បី pass state down ដូច props ទៅ child components:
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
នេះក៏ដំណើរការសម្រាប់ user-defined components:
<FormattedDate date={this.state.date} />
FormattedDate
component នឹងទទួលបាន date
នៅក្នុង props របស់ខ្លួន ហើយនឹងមិនដឹងថាតើវាមកពី Clock
state ណាមួយនោះទេ, ពី Clock
props, ឬត្រូវបានវាយដោយដៃ:
function FormattedDate(props) {
return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}
នេះត្រូវបានគេហៅជាទូទៅថា “top-down” ឬ “unidirectional” data flow. ណាមួយ state គឺតែងតែជាកម្មសិទ្ធិរបស់ជាក់លាក់របស់ component, និងណាមួយ data ឬ UI derived ពី state នោះ អាចប៉ះពាល់តែ components “below” វាតែប៉ុណ្ណោះនៅក្នុង tree.
ប្រសិនបើអ្នកស្រមៃថា component tree ដូចជា waterfall នៃ props, គ្រប់ component’s state គឺដូចជាប្រភពទឹកបន្ថែម ដែលចូលរួមជាមួយវានៅចំណុចមួយដែលបំពានប៉ុន្តែវាហូរចុះក្រោមផងដែរ.
ដើម្បីបង្ហាញថា components ទាំងអស់ ពិតជា isolated, យើងអាចបង្កើត App
component ដែល renders <Clock>
បីដង:
function App() {
return (
<div>
<Clock /> <Clock /> <Clock /> </div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Clock
មួយៗបង្កើត Timer ផ្ទាល់ខ្លួនវាហើយធ្វើបច្ចុប្បន្នភាពដោយឯករាជ្យ។
នៅក្នុងកម្មវិធី React, ថាតើ component គឺ stateful ឬ stateless គឺ ចាត់ទុកថាជាការអនុវត្ដន៍លម្អិតនៃទី component ដែលអាចផ្លាស់ប្តូរតាមពេលវេលា. លោកអ្នកអាចប្រើប្រាស់ stateless components នៅក្នុង stateful components, និងផ្ទុយមកវិញ។