[React-Native] 9. 컴포넌트 쪼개기

적자생존·2022년 11월 6일
0

React-Native

목록 보기
10/30

1. 컴포넌트 쪼개기

React-Native로 코드를 작성시 한 파일에 모든 것을 담기에는 너무 길어지기도 하고 재사용성이 없기 때문에 컴포넌트를 쪼개준다.

리액트에서 했던과 방식과 동일하며 재사용성을 통해 다른 컴포넌트에서 공통으로 사용시 작성하기 위해서 반드시 컴포넌트 쪼개기를 해주어야 한다.

2. Item 나누기

FlatList로 작성한 ToDoList Item을 먼저 나눠보자

우선 components 폴더를 하나 생성해주고 GoalItem이라는 js파일을 만들어준다.

이후 기존의 FlatList에서 render부분의 return JSX를 잘라내서 붙혀준다.

// app.js

<FlatList
          data={courseGoals}
          renderItem={(itemData) => {
            return (
              <View style={styles.goalItem}>
                <Text style={styles.goalText}>{itemData.item.text}</Text>
              </View>
            );
          }}
          keyExtractor={(item, idx) => {
            return item.id;
          }}
        />

여기서 renderItem 부분의 return 을 GoalItem.js파일로 옮긴다.

//app.js
<FlatList
          data={courseGoals}
          renderItem={(itemData) => {
            return (
              
            );
          }}
          keyExtractor={(item, idx) => {
            return item.id;
          }}
        />


// GoalItem.js

function GoalItem(){
  return(
    <View style={styles.goalItem}>
                <Text style={styles.goalText}>{itemData.item.text}</Text>
              </View>
)}

이때 반드시 스타일도 옮겨와 주어야 한다.

이제 렌더부분이 준비가 되었으니 기존의 프로퍼티에 들어간 예를 들어 text부분 등을 props로 내려준다.

// GoalItem.js

function GoalItem(props){
  return(
    <View style={styles.goalItem}>
                <Text style={styles.goalText}>{props.itemData.item.text}</Text>
              </View>
)}

이제 app.js에서 props로 내려줄 부분을 정의 해준다.

이때 GoalItem.js를 import해준다.

이때 상위 컴포넌트에서는 text라는 이름으로 props로 내려줄 것이다.

// app.js

import GoalItem from "./components/GoalItem";

<FlatList
          data={courseGoals}
          renderItem={(itemData) => {
            <GoalItem text={itemData.item.text}/>
          }}
          keyExtractor={(item, idx) => {
            return item.id;
          }}
        />

이제 GoalItem.js에 가서 props로 내려준 text라는 이름으로 변경해준다.

이때 기존의 이름을 사용하지 않고 text라고 변경해주는 이유는 다른 곳에서도 쓸때 다른 이름으로 내려줄 경우가 생길 수도 있는데 그것을 통일 시켜주기 위함이라고 할 수 있다.

function GoalItem(props){
  return(
    <View style={styles.goalItem}>
                <Text style={styles.goalText}>{props.text}</Text>
              </View>
)}

이렇게 하면 컴포넌트 쪼개기를 해준 것이다.

3. input 나누기

input도 마찬가지로 폴더를 만들고 GoalInput.js 파일을 만들어준다.

위와 마찬가지로 props 설정을 해준다.

//app.js

export default function App() {
  const [enteredGoalText, setEnteredGaolText] = useState("");
  const [courseGoals, setCourseGoals] = useState([]);
  function goalInputHandler(enteredText) {
    setEnteredGaolText(enteredText);
  }
  function addGoalHandler() {
    setCourseGoals((currentCourseGoals) => [
      ...currentCourseGoals,
      { text: enteredGoalText, id: Math.random().toString() },
    ]);
  }
  return (
    <View style={styles.appContainer}>
      <GoalInput
        goalInputHandler={goalInputHandler}
        addGoalHandler={addGoalHandler}
      />
      <View style={styles.goalsContainer}>
        <FlatList
          data={courseGoals}
          renderItem={(itemData) => {
            return <GoalItem text={itemData.item.text} />;
          }}
          keyExtractor={(item, idx) => {
            return item.id;
          }}
        />
      </View>
    </View>
  );
}
// GoalInput.js

function GoalInput(props) {
  const { goalInputHandler, addGoalHandler } = props;

  return (
    <View style={styles.inputContainer}>
      <TextInput
        style={styles.textInput}
        placeholder="Your Course goal!"
        onChangeText={goalInputHandler}
      />
      <Button title="Add Goal" onPress={addGoalHandler} />
    </View>
  );
}

위와 다르게 모두 가져온 이유는 함수부분을 props로 내려주는 방식을 보기 위함이다.

물론 위와 같이 작성하여도 렌더링 하는 부분에서는 아무런 하자 없이 돌아갈 수 있다.

하지만 이런 방식이면 다른 input을 사용할 때마다 함수를 지정하고 state를 만들어야 하기 때문에 줄이 길어진다는 단점이 있게 된다.

그렇기 때문에 공통 함수 공통 state를 만들어서 관리하게 된다.

따라서 input기능만을 하기 위해서 GoalInput.js로 가서 함수를 작성해준다.

app.js에서의 goalInputHandler함수와 State를 가져와서 onChangeText에 바인딩을 해준다.

// GoalInput.js
function GoalInput(props) {

  const [enteredGoalText, setEnteredGaolText] = useState("");
  function goalInputHandler(enteredText) {
    setEnteredGaolText(enteredText);
  }
  
  return (
    <View style={styles.inputContainer}>
      <TextInput
        style={styles.textInput}
        placeholder="Your Course goal!"
        onChangeText={goalInputHandler}
      />
      <Button title="Add Goal" onPress={props.addGoalHandler} />
    </View>
  );
}

이후 app.js에서 addGoalHandler함수를 수정해준다.

export default function App() {
  const [courseGoals, setCourseGoals] = useState([]);

  function addGoalHandler(enteredGoalText) {
    setCourseGoals((currentCourseGoals) => [
      ...currentCourseGoals,
      { text: enteredGoalText, id: Math.random().toString() },
    ]);
  }
  return (
    <View style={styles.appContainer}>
      <GoalInput addOnGoal={addGoalHandler} />
      <View style={styles.goalsContainer}>
        <FlatList
          data={courseGoals}
          renderItem={(itemData) => {
            return <GoalItem text={itemData.item.text} />;
          }}
          keyExtractor={(item, idx) => {
            return item.id;
          }}
        />
      </View>
    </View>
  );
}

기존의 addGoalHandler은 파라미터가 없었지만 파라미터를 설정해줌으로써 변화되는 값을 받을 수 있도록 만들어 준다.

하지만 이렇게만 해두면 자식 컴포넌트인 GoalInput.js에서 상태가 변경되는지 확인할 수 없게 된다.

그렇기 때문에 다시 GoalInput.js에 가서 함수를 수정해준다.

// GoalInput.js

function GoalInput(props) {

  const [enteredGoalText, setEnteredGaolText] = useState("");
  function goalInputHandler(enteredText) {
    setEnteredGaolText(enteredText);
  }
  function addGoalHandler() {
    props.addOnGoal(enteredGoalText);
  }
  return (
    <View style={styles.inputContainer}>
      <TextInput
        style={styles.textInput}
        placeholder="Your Course goal!"
        onChangeText={goalInputHandler}
      />
      <Button title="Add Goal" onPress={addGoalHandler} />
    </View>
  );
}

이후에 app.js에서 addGoalhandler 함수를 바인딩 해줘야 하는데 props.addGoalHandler(enterendGoalText)를 바인딩 해주면 무한렌더링에 걸려서 실행이 되지 않는다.

그렇기 때문에 따로 GoalInput.js에서 addGoalHandler라는 함수를 만들어서 state를 전달해주면 상위 컴포넌트에서는 state가 변경되었다는 것을 알고 함수를 실행시킬 수 있다.

profile
적는 자만이 생존한다.

0개의 댓글