-
React PatternReact 2021. 11. 30. 23:36
이 글은 React를 이용한 개발 중 가장 많이 사용되는 패턴을 정리하기 위해 작성하였습니다.< Pattern 1 >
A stateful, parent component passes down its state to a stateless, child component.
< Step >
1. Build a stateful Component Class
2. Build a stateless Component Class
3. Pass a Component's stateExample)
import React from 'react'; import ReactDOM from 'react-dom'; import { Child } from './Child'; class Parent extends React.Component { constructor(props) { super(props); this.state = { name: 'Frarthur'} } render() { return <Child name={this.state.name} />; } } ReactDOM.render(<Parent />, document.getElementById('app'))
: Parent(Stateful) Component
import React from 'react'; import ReactDOM from 'react-dom'; export class Child extends React.Component { constructor(props) { super(props); } render() { return <h1>Hey, my name is {this.props.name}</h1>; } }
: Child(Stateless) Component
+. Don't Update props
- A React component should use props to store information that can be changed, but can only be changed by a different component.
- A React component should use state to store information that the component itself can change.
ex)
import React from 'react'; class Bad extends React.Component { render() { this.props.message = 'yo'; // NOOOOOOOOOOOOOO!!! return <h1>{this.props.message}</h1>; } }
< Pattern 2 >
Child components update their parent's State
< Step >
1. Define an state-changing method on the Parent component (use this.setState or useState)
2. Pass the state-changing method down to Child component
3. Receive the Event HandlerExample)
import React from 'react'; import ReactDOM from 'react-dom'; import { Child } from './Child'; class Parent extends React.Component { constructor(props) { super(props); this.changeName = this.changeName.bind(this); this.state = { name: 'Frarthur' }; } changeName(newName) { this.setState({ name: newName }) } render() { return <Child name={this.state.name} onChange={this.changeName} /> } } ReactDOM.render( <Parent />, document.getElementById('app') );
: Parent(Stateful) Component
import React from 'react'; export class Child extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange(e) { const name = e.target.value; this.props.onChange(name); } render() { return ( <div> <h1> Hey my name is {this.props.name}! </h1> <select id="great-names" onChange={this.handleChange}> <option value="Frarthur"> Frarthur </option> <option value="Gromulus"> Gromulus </option> <option value="Thinkpiece"> Thinkpiece </option> </select> </div> ); } }
: Child(Stateless) Component
< Pattern 3 >
A Child component updates its parent's state, the parent passes that state to a sibling component.
one component for displaying the name, and a different component for allowing a user to change the name.
-> One to Display, Another to ChangeExample)
import React from 'react'; import ReactDOM from 'react-dom'; import { Child } from './Child'; import { Sibling } from './Sibling'; class Parent extends React.Component { constructor(props) { super(props); this.state = { name: 'Frarthur' }; this.changeName = this.changeName.bind(this); } changeName(newName) { this.setState({ name: newName }); } render() { return ( <div> <Child onChange={this.changeName} /> <Sibling name={this.state.name} /> </div> ); } } ReactDOM.render( <Parent />, document.getElementById('app') );
: Parent(Stateful) Component
import React from 'react'; export class Child extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange(e) { const name = e.target.value; this.props.onChange(name); } render() { return ( <div> <select id="great-names" onChange={this.handleChange}> <option value="Frarthur">Frarthur</option> <option value="Gromulus">Gromulus</option> <option value="Thinkpiece">Thinkpiece</option> </select> </div> ); } }
: Child(Stateless) Component
import React from 'react'; export class Sibling extends React.Component { render() { const name = this.props.name; return ( <div> <h1>Hey, my name is {name}!</h1> <h2>Don't you think {name} is the prettiest name ever?</h2> <h2>Sure am glad that my parents picked {name}!</h2> </div> ); } }
: Sibling(Stateless) Component
< Pattern 4 >
Separating container components from presentational components.
When one component has too many responsibilities.
That is, If a component has to have state, make calculations based on props, or manage any other complex logic, then that component shouldn’t also have to render HTML-like JSX.< Step >
1. Identifiy that the original component was handling both calculations/logic and presentation/rendering
2. Copy the original component to a new container(or presentational) component file.
3. Remove all of the presentation/rendering code from the container component.
4. Remove all of the calculation/logic code from the presentational component.
5. Accesse the presentational component from withing the container using import, export
6. Edit the container's render( ) method to render the presentational component with proper propsimport React from 'react'; import ReactDOM from 'react-dom'; const GUINEAPATHS = [ 'https://content.codecademy.com/courses/React/react_photo-guineapig-1.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-2.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-3.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-4.jpg' ]; export class GuineaPigs extends React.Component { constructor(props) { super(props); this.state = { currentGP: 0 }; this.interval = null; this.nextGP = this.nextGP.bind(this); } nextGP() { let current = this.state.currentGP; let next = ++current % GUINEAPATHS.length; this.setState({ currentGP: next }); } componentDidMount() { this.interval = setInterval(this.nextGP, 5000); } componentWillUnmount() { clearInterval(this.interval); } render() { let src = GUINEAPATHS[this.state.currentGP]; return ( <div> <h1>Cute Guinea Pigs</h1> <img src={src} /> </div> ); } } ReactDOM.render( <GuineaPigs />, document.getElementById('app') );
: Original Component
import React from 'react'; const GUINEAPATHS = [ 'https://content.codecademy.com/courses/React/react_photo-guineapig-1.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-2.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-3.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-4.jpg' ]; export class GuineaPigs extends React.Component { render() { let src = this.props.src; return ( <div> <h1>Cute Guinea Pigs</h1> <img src={src} /> </div> ); } }
: Presentational Component
import React from 'react'; import ReactDOM from 'react-dom'; import { GuineaPigs } from '../components/GuineaPigs'; const GUINEAPATHS = [ 'https://content.codecademy.com/courses/React/react_photo-guineapig-1.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-2.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-3.jpg', 'https://content.codecademy.com/courses/React/react_photo-guineapig-4.jpg' ]; class GuineaPigsContainer extends React.Component { constructor(props) { super(props); this.state = { currentGP: 0 }; this.interval = null; this.nextGP = this.nextGP.bind(this); } nextGP() { let current = this.state.currentGP; let next = ++current % GUINEAPATHS.length; this.setState({ currentGP: next }); } componentDidMount() { this.interval = setInterval(this.nextGP, 5000); } componentWillUnmount() { clearInterval(this.interval); } render() { const src = GUINEAPATHS[this.state.currentGP]; return <GuineaPigs src={src} />; } } ReactDOM.render( <GuineaPigsContainer />, document.getElementById('app') );
: Container Component
'React' 카테고리의 다른 글
Function Components (0) 2021.12.05 Component Lifecycle (0) 2021.12.02 React Useful Tools (0) 2021.11.24 State (0) 2021.10.30 this.props (0) 2021.10.30