본문 바로가기
typescript

[typescript] react-typscript(usereducer)

by 남민섭 2023. 2. 24.
728x90
반응형
반응형

useReducer 사용하기


reducer 함수 생성

올수 있는 액션객체를 유니언 타입으로 쭉 나열

type Action = {type: 'INCREASE'} | {type: 'DECREASE'}
function reducer(state: number, action: Action): number {   

//카운터를 바꿀거기때문에 상태하고 리턴값 타입은 number
}

 

연습해보기 실습

 

 

App.tsx

import React from "react";
import ReducerSample from "./components/ReducerSample";

function App() {
  return (
    <div className="App">
      <ReducerSample />
    </div>
  );
}

export default App;

 

components폴더안에

ReducerSample.tsx

///리듀서 연습을 위해서 만듬

import React, { useReducer } from 'react';

//color를 타입으로 지정
type Color = 'red' | 'pink' | 'yellow';
//상태타입 지정
type State = {
    count: number;
    text: string;
    color: Color;
    isGood: boolean
}
//액션타입 지정
type Action = {type: 'SET_COUNT'; count: number}
| {type: 'SET_TEXT'; text: string}
| {type: 'SET_COLOR'; color: Color}
| {type: 'SET_GOOD'}

//매개변수는 타입지정!!!
//리턴값이 있는 경우 리턴값의 타입을 지정
function reducer(state: State, action: Action) : State{   //reducer는 새로운 상태를 리턴해줌!!! 리턴값 있음
    switch(action.type){
        case "SET_COUNT":
            return {
                ...state,
                count: action.count
            }
        case "SET_COLOR":
            return {
                ...state,
                color: action.color
            }    
        case "SET_TEXT":
            return {
                ...state,
                text: action.text
            }
        case "SET_GOOD":
            return {
                ...state,
                isGood: !state.isGood
            }      
        default:
            return state;    
    }
}

const ReducerSample = () => {
    const [state, dispatch] = useReducer(reducer, {
        count:0,
        text: "green",
        color: "pink",
        isGood: true
    })
    const setCount = () => {
        dispatch({type: "SET_COUNT", count: 5})
    }
    const setText = () => {
        dispatch({type: "SET_TEXT", text: "blue"})
    }
    const setColor = () => {
        dispatch({type: "SET_COLOR", color: "yellow"})
    }
    const setToggle = () => {
        dispatch({type: "SET_GOOD"})
    }
    return (
        <div>
            <p>count: {state.count}</p>
            <p>text: {state.text }</p>
            <p>color: {state.color}</p>
            <p>isGood: {state.isGood ? "true": "false"}</p>
            <div>
                <button onClick={setCount}>SET_COUNT</button>
                <button onClick={setText}>SET_TEXT</button>
                <button onClick={setColor}>SET_COLOR</button>
                <button onClick={setToggle}>SET_ISGOOD</button>
            </div>
        </div>
    );
};

export default ReducerSample;

 

 

 


 

todolist 실습

 

 

 

App.tsx

import React, { useReducer } from 'react';
import './App.css';
import InputTodo from './components/InputTodo';
import TodoLists from './components/TodoLists';


const initialState = [
  {
    id: 1,
    text: "이력서, 자소서 쓰기",
    isDone: false
  },
  {
    id: 2,
    text: "이력서, 자소서 쓰기",
    isDone: false
  },
  {
    id: 3,
    text: "이력서, 자소서 쓰기",
    isDone: false
  }
]

type Action = "ADDTODO"|  "DELTODO"| "TOGGLETODO"
interface actionType {
  type: Action;
  todo?: dataType;
  id? : number;
}
export interface dataType {
  id: number;
  text: string;
  isDone: boolean;
}
function reducer(state: dataType[], action: actionType): dataType[] {
  switch(action.type){
    case "ADDTODO":
      return [
        ...state,
        action.todo!  //!는 null과 undefiend가 오지 않는다는 의미 값이 무조건 온다
      ];
    case "DELTODO":
      return (state as Array<dataType>).filter(li=>li.id !== action.id);
    case "TOGGLETODO":
      return (state as Array<dataType>).map(li=> li.id === action.id ? { 
        //인터페이스를 만들어주고 state는 array<datatype>이라고 지정
        ...li, isDone: !li.isDone}: li)
    default:
      return state;      
  }
}

function App() {
  const [todos, dispatch] =  useReducer(reducer, initialState)
  console.log(todos)
  const onAdd = (todo:dataType) => {
    dispatch({
      type: "ADDTODO",
      todo: todo
    })
  }
  const onToggletodo = (id:number) => {
    dispatch({type: "TOGGLETODO", id: id})
  }
  const onDeltodo = (id:number) => {
    dispatch({type:"DELTODO", id: id})
  }
  
  return (
    <div className="App">
      <InputTodo onAdd={onAdd}/>
      <TodoLists todos={todos} 
      onToggletodo = {onToggletodo}
      onDeltodo = {onDeltodo}/>
    </div>
  );
}

export default App;

 

components 폴더 생성

InputTodo.tsx

import React, { useRef, useState } from 'react';
import { dataType } from '../App';

interface InputProps {
    onAdd: (todo:dataType) => void
}

const InputTodo = ({onAdd}: InputProps) => {
    const [todoState, setTodoState] = useState("")

    const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        console.log(e)
        setTodoState(e.target.value)
    }
    const todoid = useRef(4) //객체를 리턴해줌  {current : 4}
    const onClick = () =>{
        onAdd({
            id: todoid.current,
            text: todoState,
            isDone: false
        })
        setTodoState("")
        todoid.current++;
    }
    return (
        <div>
            <input name="name" value={todoState} onChange={onChange}/>
            <button onClick={onClick}>등록</button>
        </div>
    );
};

export default InputTodo;

 

TodoLists.tsx

import React from 'react';
import { dataType } from '../App';


interface todoProps {
    todos: dataType[]
    onToggletodo: (id:number)=>void
    onDeltodo: (id:number)=> void
}


const TodoLists = ({todos, onToggletodo, onDeltodo}: todoProps) => {
    return (
        <div>
           <ul>
                {todos.map(todo =><li key={todo.id} 
                style={{background: todo.isDone ? "yellow" : undefined, listStyle: "none"}}>
                    <span onClick={()=>{onToggletodo(todo.id)}}>{todo.text}</span>
                    <button onClick={()=>{onDeltodo(todo.id)}}>삭제</button></li>)}
            </ul> 
        </div>
    );
};

export default TodoLists;
728x90
반응형

댓글