jineecode

props & state 본문

React native

props & state

지니코딩 2021. 7. 3. 13:42

함수형 

 

1. button component

https://fonts.google.com/icons?selected=Material+Icons

 

Google Fonts

Making the web more beautiful, fast, and open through great typography

fonts.google.com

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
Comments