React - Lifecycle - 05

React - Lifecycle - 05

Lifecycle Methods

Component Lifecycle

  1. constructor(Good place to do one-time setup)
  2. render(Avoid doing anything besides returning JSX)
  3. (content visible on screen)
  4. componentDidMount(Good place to do data-loading!)
  5. (Sit and wait for updates…)
  6. componentDidUpdate(Good place to do more data-loading when state/props change)
  7. (Sit and wait until this component is not longer shown)
  8. componentWillUnmount(Good place to do cleanup - especially for non-React stuff)
componentDidMount() {
 console.log('My component was rendered to the screen');
}

componentDidUpdate() {
 console.log('My component was just updated - it rendered!');
}

Other lifecycle methods(rarely used)

  • shouldComponentUpdate
  • getDerivedStateFromProps
  • getShanpshotBeforeUpdate

Reactoring Data Loading to Lifecycle Methods

constructor에 있는 geolocation 함수를 componentDidMount() 함수로 이동한다.

componentDidMount() { // render된 후에 정보를 가져오도록 한다.
 window.navigator.geolocation.getCurrentPosition(
 position  =>  this.setState({ lat:  position.coords.latitude }),
 err  =>  this.setState({ errorMessage:  err.message })
 );
}

Alternate State Initialization

class  App  extends  React.Component {
 constructor(porps) {
  super(props);
  
  this.state = { lat:  null };
 }
}
// 위의 방법과 아래의 방법은 state를 초기화하는 방법이다.(babel이 자동적으로 변환해준다.)

class  App  extends  React.Component {
 state = { lat:  null };
}

Passing State as Props

// index.js
render() {
 return  <SeasonDisplay  lat={this.state.lat}  />  // this
}

// SeasonDisplay.js
import  React  from  'react';

const  getSeason = (lat, month) => {
 if (month > 2 && month < 9) {
  return  lat > 0 ? 'summer' : 'winter';
 } else {
  return  lat > 0 ? 'winter' : 'summer';
 }
} 

const  SeasonDisplay = props  => {
 const  season = getSeason(props.lat, new  Date().getMonth());

 return (
  <div>season display!</div>
 );
};

export  default  SeasonDisplay;

Ternary Expressions in JSX

season 값에 따라 출력하는 문장을 다르게 하고 싶다면 return()안에 if문을 사용해도 되지만 삼항 연산자를 사용하여 바로 적용 가능하다.
const  SeasonDisplay = props  => {
 const  season = getSeason(props.lat, new  Date().getMonth());
 const  text = season === 'winter' ? 'Burr, it is chilly' : 'Lets hit the beach'

 return (
  <div>
   <h1>{text}</h1>
  </div>
 );
};
아이콘을 추가하고 싶다면 아래와 같이 수정한다.
const  SeasonDisplay = props  => {
 const  season = getSeason(props.lat, new  Date().getMonth());
 const  text = season === 'winter' ? 'Burr, it is chilly' : 'Lets hit the beach'
 const  icon = season === 'winter' ? 'snowflake' : 'sun'  // this

 return (
  <div>
   <i  className={`${icon} icon`}  /> // this
   <h1>{text}</h1>
   <i  className={`${icon} icon`}  />
  </div>
 );
};

Extracting Options to Config Objects

중복되는 코드가 있다. 이 코드는 config로 정의하여 코드를 수정한다.
import  React  from  'react';

const  seasonConfig = { // configuration
 summer: {
 text:  'Lets hit the beach',
 iconName:  'sun'
 },
 winter: {
 text:  'Burr, it is chiily',
 iconName:  'snowflake'
 }
};

const  getSeason = (lat, month) => {
 if (month > 2 && month < 9) {
  return  lat > 0 ? 'summer' : 'winter';
 } else {
  return  lat > 0 ? 'winter' : 'summer';
 }
} 

const  SeasonDisplay = props  => {

 const  season = getSeason(props.lat, new  Date().getMonth());
 const {text, iconName } = seasonConfig[season]; // this

 return (
  <div>
   <i  className={`${iconName} icon`}  />
   <h1>{text}</h1>
   <i  className={`${iconName} icon`}  />
  </div>

 );
};

export  default  SeasonDisplay;

Adding some Styles

// SeasonDisplay.js
import  './SeasonDisplay.css';

return (
 <div  className={`season-display ${season}`}> // this
  <i  className={`icon-left massive ${iconName} icon`}  />
  <h1>{text}</h1>
  <i  className={`icon-right massive ${iconName} icon`}  />
 </div>
);
/* SeasonDisplay.css */
.icon-left {
 position: absolute;
 top: 10px;
 left: 10px;
}
  
.icon-right {
 position: absolute;
 bottom: 10px;
 right: 10px;
}

.season-display.winter  i {
 color: blue;
}

.season-display.summer  i {
 color: red;
}

.season-display {
 display: flex;
 justify-content: center;
 align-items: center;
 height: 100vh;
}
 
.winter {
 background-color: aliceblue;
}

.summer {
 background-color: orange;
}
screen

Showing Loading Spinner

기존의 Loading 문자열을 Spinner로 대체한다.
// index.js
return  <Spinner  />

// Spinner.js
import  React  from  'react';

const  Spinner = () => {
 return (
  <div  className="ui active dimmer">
   <div  className="ui big text loader">
    Loading...
   </div>
  </div>
 );
};

export  default  Spinner;

Specifying Default Props

// index.js
return <Spinner  message="Please accept location request" />

// Spinner.js
import  React  from  'react';

const  Spinner = props  => {
 return (
  <div  className="ui active dimmer">
   <div  className="ui big text loader">
    {props.message}
   </div>
  </div>
 );
};

Spinner.defaultProps = { // this
 message:  'Loading...'
};

export  default  Spinner;

Avoiding Conditionals in Render

import  React  from  'react';
import  ReactDOM  from  'react-dom';
import  SeasonDisplay  from  './SeasonDisplay';
import  Spinner  from  './Spinner';
  
class  App  extends  React.Component {
 state = { lat:  null, errorMessage:  '' };
  
 componentDidMount() {
  window.navigator.geolocation.getCurrentPosition(
   position  =>  this.setState({ lat:  position.coords.latitude }),
   err  =>  this.setState({ errorMessage:  err.message })
  );
 }
 
 renderContent() {
  if (this.state.errorMessage && !this.state.lat) {
   return <div>Error: {this.state.errorMessage}</div>
  }

  if (!this.state.errorMessage && this.state.lat)    {
   return <SeasonDisplay  lat={this.state.lat} />
  }

 return <Spinner  message="Please accept location request" />
 }
 
 // React says we have to define render!!
 render() {
  return (
   <div  className="border red"> // renderContent()를 사용하지 않으면 return할 때, className을 반복적으로 지정해주어야 하지만 이 코드는 중복 없이 className을 지정할 수 있는 방법이다.
    {this.renderContent()} // this
   </div>
  )
 }
}
 
ReactDOM.render(<App />, document.querySelector('#root'))

GitHub and Others

댓글

가장 많이 본 글