jineecode
props & state 본문
함수형
1. button component
https://fonts.google.com/icons?selected=Material+Icons
add_circle, remove_circle 사용
RN에서는 이미지 이름을 add.png, add@2x.png, add@3x.png 으로 이름을 변경해두면 해당 화면 사이즈에 맞는 이미지를 자동으로 불러온다.
src/Components/Button/index.tsx
import React from 'react';
import Styled from 'styled-components/native';
const Container = Styled.TouchableOpacity``;
const Icon = Styled.Image``;
interface Props {
iconName: 'plus' | 'minus';
onPress?: () => void;
}
const Button = ({ iconName, onPress }: Props) => {
return (
<Container onPress={onPress}>
<Icon
source={
iconName === 'plus'
? require('../../Assets/Images/add.png')
: require('../..//Assets/Images/remove.png')
}
/>
</Container>
);
};
export default Button;
1) RN 의 TouchableOpacity, Image 컴포넌트를 사용하여 구현.
1-1) TouchableOpacity : onPress의 Props(속성값)을 가지고 있음
1-2) Image : source Props를 가지고 있음. HTML의 Image 태그와는 다르게 require 구문을 사용한다.
2) Button 컴포넌트는 iconName과 onPress 두 가지의 props를 가지고 있는데 이는 다른 컴포넌트(Button 컴포넌트를 import 하여 사용하는 컴포넌트) 에서 값을 지정할 예정
3) TS를 이용하여 (interface props) Button 의 props 타입 (iconName, onPress)을 지정한다.
iconName은 plus 혹은 minus 여야하고, onPress는 꼭 지정해주지 않아도 된다.
3-1) iconName === 'plus' 가 참이면 add.png 이미지를, 거짓이면 remove.png 이미지를 렌더링 할 것이다.
2. Counter 컴포넌트
src/Screens/Counter/index.tsx
import React, { useState } from 'react';
import Styled from 'styled-components/native';
import Button from '../../Components/Button';
const Container = Styled.SafeAreaView`
flex: 1;
`;
const TitleContainer = Styled.View`
flex: 1;
justify-content: center;
align-items: center;
`;
const TitleLabel = Styled.Text`
font-size: 24px;
`;
const CountContainer = Styled.View`
flex: 2;
justify-content: center;
align-items: center;
`;
const CountLabel = Styled.Text`
font-size: 24px;
font-weight: bold;
`;
const ButtonContainer = Styled.View`
flex: 1;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
`;
interface Props {
title?: string;
initValue: number;
}
const Counter = ({ title, initValue }: Props) => {
const [count, setCount] = useState<number>(initValue);
return (
<Container>
{title && (
<TitleContainer>
<TitleLabel>{title}</TitleLabel>
</TitleContainer>
)}
<CountContainer>
<CountLabel>{count}</CountLabel>
</CountContainer>
<ButtonContainer>
<Button iconName="plus" onPress={() => setCount(count + 1)} />
<Button iconName="minus" onPress={() => setCount(count - 1)} />
</ButtonContainer>
</Container>
);
};
export default Counter;
1) Counter 컴포넌트의 Props : title?, initValue. title은 string이고, initValue는 number이다.
2) count를 변경하기 위해 state 훅 설정. state에도 ts로 타입을 확인할 수 있다. 구문은 다음과 같다.
const [변수명, 변경될 set 함수] = useState<state의 타입>(초기 값);
3) 버튼 태그에는 button 컴포넌트에서 코드했던 바와 같이 iconName props 을 필수적으로 적어주고 plus라면 plus 이미지가 나오도록, 아니라면 minus이미지가 나오도록 코딩한다.
4) src/App.tsx
import React from 'react';
import Styled from 'styled-components/native';
import Counter from './Screens/Counter';
const Container = Styled.View`
flex: 1;
background-color: #EEE;
`;
const App = () => {
return (
<Container>
<Counter title="This is a Counter App" initValue={5} />
</Container>
);
};
export default App;
1) title은 counter 컴포넌트에서 interface로 지정했듯 필수요소가 아니므로 코딩하지 않아도 에러가 뜨지 않는다.
반면 initValue는 넘버값을 넣어주어야만 에러가 뜨지 않는다.
클래스형
import React, { useState } from 'react';
import Styled from 'styled-components/native';
import Button from '../../Components/Button';
const Container = Styled.SafeAreaView`
flex: 1;
`;
const TitleContainer = Styled.View`
flex: 1;
justify-content: center;
align-items: center;
`;
const TitleLabel = Styled.Text`
font-size: 24px;
`;
const CountContainer = Styled.View`
flex: 2;
justify-content: center;
align-items: center;
`;
const CountLabel = Styled.Text`
font-size: 24px;
font-weight: bold;
`;
const ButtonContainer = Styled.View`
flex: 1;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
`;
interface Props {
title?: string;
initValue: number;
}
interface State {
count: number;
error: boolean;
}
class Counter extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
console.log('constructor');
this.state = {
count: props.initValue,
error: false,
};
}
render() {
console.log('render');
const { title } = this.props;
const { count, error } = this.state;
return (
<Container>
{!error && (
<>
{title && (
<TitleContainer>
<TitleLabel>{title}</TitleLabel>
</TitleContainer>
)}
<CountContainer>
<CountLabel>{count}</CountLabel>
</CountContainer>
<ButtonContainer>
<Button
iconName="plus"
onPress={() => this.setState({ count: count + 1 })}
/>
<Button
iconName="minus"
onPress={() => this.setState({ count: count - 1 })}
/>
</ButtonContainer>
</>
)}
</Container>
);
}
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
console.log('getDerivedStateFromProps');
return null;
}
componentDidMount() {
console.log('componentDidMount');
}
shouldComponentUpdate(nextProps: Props, nextState: State) {
console.log('shouldComponentUpdate');
return true;
}
getSnapshotBeforeUpdate(prevProps: Props, prevState: State) {
console.log('getSnapshotBeforeUpdate');
return null;
}
componentDidUpdate(prevProps: Props, prevState: State, snapshot: null) {
console.log('componentDidUpdate');
}
componentWillUnmount() {
console.log('componentWillUnmount');
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
this.setState({
error: true,
});
}
}
export default Counter;
클래스형은 state의 타입을 미리 정의하고 컴포넌트 선언 시 해당 타입을 지정해준다.
(함수형은 useState로 State를 생성할 때 초기값 지정)
interface State {
count: number;
}
class Counter extends React.Component<Props, State>
클래스 컴포넌트에서는 생성자함수(constructor)에서 state의 초기값을 설정한다.
constructor(props: Props) {
super(props);
console.log('constructor');
this state = {
count: props.initValue,
}
}
생성자 함수를 사용할 때는 항상 super(props);를 사용하여 부모 컴포넌트(React.Component)의 생성자 함수를 호출해야 한다.
state에 접근하기 위해서는 this를 사용하며, 이를 변경하고자 할 때는 this.setState로 값을 변경한다.
'React native' 카테고리의 다른 글
RN 새로운 프로젝트 생성하기 (0) | 2021.07.10 |
---|---|
todolist (0) | 2021.07.03 |
AsyncStorage 사용 (0) | 2021.07.03 |
개발환경 세팅 (0) | 2021.06.26 |
install (0) | 2021.06.21 |