도리쓰에러쓰

[React] Redux1 :: props 대신 사용하기 본문

코딩애플 (React)/기초수업(코딩애플) - 3

[React] Redux1 :: props 대신 사용하기

강도리 2022. 1. 26. 22:18

저번 게시물에 이어서 작성하겠습니다. (코드 참고)

 

[React] Tab 만들기와 리액트에서의 등장 애니메이션

저번 게시물에 이어서 작성하겠습니다. (코드 참고) [React] Component가 많을 땐 Context API 사용하기 저번 게시물에 이어서 작성하겠습니다. (코드 참고) [React] Component 3개 중첩하여 만들고 state 전달하

dori-coding.tistory.com


1. cart 페이지 만들기

1️⃣ Cart.js 파일 생성 후 아래 코드를 작성합니다.

import React from 'react';
import { Table } from 'react-bootstrap';

function Cart() {
    return(
        <div>
            <Table responsive>
                <thead>
                    <tr>
                        <th>#</th>
                        <th>상품명</th>
                        <th>수량</th>
                        <th>변경</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>1</td>
                        <td>Table cell</td>
                        <td>Table cell</td>
                        <td>Table cell</td>
                    </tr>
                </tbody>
            </Table>
        </div>
    )
}

export default Cart;

 

 

2️⃣ App.js에서 Cart.js를 import합니다.

import Cart from './Cart.js';

 

 

3️⃣ App.js에서 <Route>를 하나 추가합니다.

  * localhost:포트번호/cart 로 접속이 가능해집니다.

<Route path="/:id">
    <div>아무말</div>
</Route>

2. Redux 이용하여 데이터바인딩하기

1️⃣ 터미널에서 npm install redux react-redux 혹은

yarn이 설치되어 있으신 분들은 yarn add redux react-redux를 입력하여 redex와 react-redux를 동시에 설치합니다.

 

 

2️⃣ index.html에서 Provider를 import합니다.

import { Provider } from 'react-redux';

 

 

3️⃣ <Provider>로 <App />을 감쌉니다.

  💡 감싸진 <App /> Component는 props 없이도 state 공유가 가능합니다.

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

 

 

4️⃣ createStore() 안에 state 저장하기 위해 createStore import하고 변수를 생성합니다.

  그리고 createStrore() 안에 상품 정보 state를 return하는 함수를 생성합니다.

import { createStore } from 'redux';

let store = createStore(()=>{ 
  return [
    { id : 0, name : 'white bag', quan : 2 }, 
    { id : 1, name : 'black bag', quan : 5 }, 
    { id : 2, name : 'red bag', quan : 0 }
  ]
});

 

 

5️⃣ <Provider>에 변수 store를 props 전송합니다.

<Provider store={store}>

 

 

6️⃣ Component에서 변수 store에 있는 state를 사용하려면 아래의 방법으로 하면 됩니다.

 

1) function 만들기

function store(state){}

 

2) export default Component명; 주석 처리하기

// export default Cart;

 

3) export default connect(함수명)(Component명) 작성하기

export default connect(store)(Cart)

 

4) connect import하기

import { connect } from 'react-redux';

 

5) store 데이터를 props로 등록하기

function store(state){
    return {
        state : state
    }
}

  - 이 function은 redux store 데이터 가져와서 props로 변환해주는 함수입니다.

  - state를 props화 시켜준다고 생각하면 됩니다.

 

6) Cart Component에 props로 받아서 map()으로 반복문 돌려 데이터 출력하기

function Cart(props) {
    return(
        <div>
            <Table responsive>
                <thead>
                    <tr>
                        <th>#</th>
                        <th>상품명</th>
                        <th>수량</th>
                        <th>변경</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        props.state.map((a, i)=>{
                            return(
                                <tr key={i}>
                                    <td>{ a.id }</td>
                                    <td>{ a.name }</td>
                                    <td>{ a.quan }</td>
                                    <td></td>
                                </tr>
                            )
                        })
                    }
                </tbody>
            </Table>
        </div>
    )
}

 

- 아래 사진과 같이 store에 있던 state 데이터가 들어온 것을 확인할 수 있습니다.

 

🔔 Redux 쓰는 이유

깊은 하위 Component들도 props 여러번 전송없이 state를 직접 갖다쓸 수 있기 때문에 데이터 사용이 용이합니다.


3. 전체 코드

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import { BrowserRouter } from 'react-router-dom';

import { Provider } from 'react-redux';
import { createStore } from 'redux';

let store = createStore(()=>{ 
  return [
    { id : 0, name : 'white bag', quan : 2 }, 
    { id : 1, name : 'black bag', quan : 5 }, 
    { id : 2, name : 'red bag', quan : 0 }
  ]
});

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

 

App.js

/* eslint-disable */
import React, { useState, useContext } from 'react'
import { Navbar, Container, Nav, NavDropdown, Button } from 'react-bootstrap';
import './App.css';
import data from './data.js';
import Detail from './Detail.js';
import axios from 'axios';

import { Link, Route, Switch } from 'react-router-dom';

import Cart from './Cart.js';

export let inventoryContext = React.createContext();

function App() {

  let [products, setProducts] = useState(data);
  let [inventory, setInventory] = useState([10, 11, 12]);

  return (
    <div className="App">
      <Navbar bg="light" expand="lg">
        <Container>
          <Navbar.Brand href="#home">Saint Laurent</Navbar.Brand>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="me-auto">
              <Nav.Link as={Link} to="/">Home</Nav.Link>
              <Nav.Link as={Link} to="/detail">Detail</Nav.Link>
              <NavDropdown title="Dropdown" id="basic-nav-dropdown">
                <NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
                <NavDropdown.Item href="#action/3.2">Another action</NavDropdown.Item>
                <NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
                <NavDropdown.Divider />
                <NavDropdown.Item href="#action/3.4">Separated link</NavDropdown.Item>
              </NavDropdown>
            </Nav>
          </Navbar.Collapse>
        </Container>
      </Navbar>

      <Switch>
        <Route exact path="/">
          <div className='Jumbotron'>
            <h1>20% Season Off</h1>
            <p>
              This is a simple hero unit, a simple jumbotron-style component for calling
              extra attention to featured content or information.
            </p>
            <p>
              <Button variant="primary">Learn more</Button>
            </p>
          </div>

          <div className='container'>

            <inventoryContext.Provider value={inventory}>
              <div className='row'>
                {
                  products.map((a, i) => {
                    return <Card products={a} num={i} key={i}/>
                  })
                }
              </div>
            </inventoryContext.Provider>

            <button className='btn btn-primary' onClick={()=>{
              axios.get('https://codingapple1.github.io/shop/data2.json')
              .then((result)=>{
                setProducts([...products, ...result.data]) 
              })
              .catch(()=>{
                console.log('fail');
              })
            }}>더보기</button>
          </div>
        </Route>
        
        <Route path="/detail/:id">
          <inventoryContext.Provider value={inventory}>
            <Detail products={ products } inventory={ inventory } setInventory={ setInventory } />
          </inventoryContext.Provider>
        </Route>
        
        <Route path="/cart">
            <Cart></Cart>
        </Route>

        <Route path="/:id">
            <div>아무말</div>
        </Route>
      </Switch>
    </div>
  );
}

function Card(props) {

  let inventory = useContext(inventoryContext);

  return(
    <div className='col-md-4'>
      <img className="img" src={ 'images/img'+ (props.num + 1) +'.jpg' } />
      <h4>{ props.products.title }</h4>
      <p>{ props.products.content }</p>
      <p>{ props.products.price }</p>
      <p>재고 : { inventory[props.num] }</p>
    </div>
  )
}

export default App;

 

 

Cart.js

import React from 'react';
import { Table } from 'react-bootstrap';
import { connect } from 'react-redux';

function Cart(props) {
    return(
        <div>
            <Table responsive>
                <thead>
                    <tr>
                        <th>#</th>
                        <th>상품명</th>
                        <th>수량</th>
                        <th>변경</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        props.state.map((a, i)=>{
                            return(
                                <tr key={i}>
                                    <td>{ a.id }</td>
                                    <td>{ a.name }</td>
                                    <td>{ a.quan }</td>
                                    <td></td>
                                </tr>
                            )
                        })
                    }
                </tbody>
            </Table>
        </div>
    )
}

function store(state){
    return {
        state : state
    }
}

export default connect(store)(Cart)
// export default Cart;

 

* 이외의 코드는 이전 게시물에 작성된 코드와 일치합니다.

Comments