An open API service indexing awesome lists of open source software.

https://github.com/ssi02014/next-tutorial-redux-scss

๐Ÿ˜ŠNext.js๋กœ Redux(Redux-Saga), Scss Setting
https://github.com/ssi02014/next-tutorial-redux-scss

javacript nextjs react scss

Last synced: 8 months ago
JSON representation

๐Ÿ˜ŠNext.js๋กœ Redux(Redux-Saga), Scss Setting

Awesome Lists containing this project

README

          

# ๐Ÿ’ป Next-Tutorial-Redux-Scss
### Next.js์— Redux-Saga์™€ Sass ์ ์šฉ


## ๐ŸŽฅ ์ฐธ๊ณ  YouTube
### ๐Ÿ”– https://www.youtube.com/watch?v=UXMGGI3TSs4&t=622s


## ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป Install
- yarn add @zeit/next-sass node-sass@4.14.1
- yarn add next-redux-saga next-redux-wrapper react-redux redux redux-devtools-extension redux-saga
- ๋ค์œผ๋กœ yarn add redux-thunk


## ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป Sass
- next.js์— sass๋ฅผ ์ ์šฉํ•˜๋ ค๋ฉด @zeit/next-sass ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€๋กœ Installํ•ด์•ผ ๋˜๋ฉฐ, .next.config.js๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ๋œ๋‹ค.
- ๊ทธ๋ฆฌ๊ณ  _app.js์— import "../scss/main.scss"; ๋ฅผ ํ•˜๋ฉด ๋œ๋‹ค.


### ๐Ÿƒ .next.config.js
```js
const withSass = require("@zeit/next-sass");

module.exports = withSass({
cssModules: true,
});
```


## ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป Redux-Saga
### ๐Ÿƒ store.js
- composeWithDevTools: redux devtools๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ
- createSagaMiddleware: redux-saga ์ƒ์„ฑ
- createStore: Store ์ƒ์„ฑ
- applyMiddleware: ๋ฏธ๋“ค์›จ์–ด ์ ์šฉ


```js
import { createStore, compose, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import createSagaMiddleware from "redux-saga";

import rootReducer from "./reducers";
import rootSaga from "./sagas";

//redux-saga ์ƒ์„ฑ
const sagaMiddleware = createSagaMiddleware();

//์ดˆ๊ธฐ initailState
const initialState = {};

//๋ฏธ๋“ค์›จ์–ด ์—ฐ๊ฒฐ
const middleware = [sagaMiddleware];

//๊ฐœ๋ฐœ ๋ชจ๋“œ๋ผ๋ฉด composeWithDevTools
//๋ฐฐํฌ ๋ชจ๋“œ๋ผ๋ฉด compose
const enhancer =
process.env.NODE_ENV === "production"
? compose(applyMiddleware(...middleware))
: composeWithDevTools(applyMiddleware(...middleware));

//store ์ƒ์„ฑ
const store = createStore(rootReducer, initialState, enhancer);

//store์— rootSaga๋ฅผ ๋„ฃ์€ sagaMiddleware๋ฅผ ์‹คํ–‰
store.sagaTask = sagaMiddleware.run(rootSaga);

export default store;
```

### ๐Ÿƒ _app.js
- Component๋ฅผ Provider๋กœ ๋ฌถ์–ด์ฃผ๋ฉด ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ redux store๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
- createWrapper: getServerSideProps, getStaticProps ๊ฐ™์€ next์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์— redux๋ฅผ ๊ฒฐํ•ฉ์‹œํ‚ค๋Š” ์—ญํ• . ๋”ฐ๋ผ์„œ, wrapper.withRedux๋กœ ํŽ˜์ด์ง€๋ฅผ ๊ฐ์‹ธ๊ฒŒ ๋˜๋ฉด redux๊ฐ€ ๊ฒฐํ•ฉ๋œ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ


```js
import "../styles/globals.css";
import React from "react";
import { Provider } from "react-redux";
import { createWrapper } from "next-redux-wrapper";
import store from "../store/store";
import "../scss/main.scss";

function MyApp({ Component, pageProps }) {
return (

;

);
}

const makestore = () => store;
const wrapper = createWrapper(makestore);

export default wrapper.withRedux(MyApp);
```


### ๐Ÿƒ sagas/index.js
- all: ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ๋ฐฐ์—ด์˜ ํ˜•ํƒœ๋กœ ์ธ์ž๋กœ ๋„ฃ์–ด์ฃผ๋ฉด, ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋“ค์ด ๋ณ‘ํ–‰์ ์œผ๋กœ ๋™์‹œ์— ์‹คํ–‰๋˜๊ณ , ์ „๋ถ€ resolve๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
- call: ํ•จ์ˆ˜์˜ ๋™๊ธฐ์ ์ธ ํ˜ธ์ถœ์„ ํ•  ๋•Œ ์‚ฌ์šฉ
- fork: ํ•จ์ˆ˜์˜ ๋น„๋™๊ธฐ์ ์ธ ํ˜ธ์ถœ์„ ํ•  ๋•Œ ์‚ฌ์šฉ(์ฆ‰, call๊ณผ ๋‹ค๋ฅด๊ฒŒ ์ˆœ์„œ ์ƒ๊ด€์—†์ด ์‹คํ–‰ํ•ด์•ผ๋  ๋•Œ ์‚ฌ์šฉ)


```js
import { all, fork } from "redux-saga/effects";
import postSaga from "./postSaga";

//์ œ๋„ˆ๋ ˆ์ดํ„ฐ
export default function* rootSaga() {
yield all([fork(postSaga)]);
}
```


### ๐Ÿƒ sagas/postSaga.js
- put: dispatch์™€ ๊ฐ™์€ ์—ญํ• ์„ ํ•œ๋‹ค.
- takeEvery: ๋“ค์–ด์˜ค๋Š” ๋ชจ๋“  ์•ก์…˜์— ๋Œ€ํ•ด ํŠน์ • ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
- takeLatest: ๊ธฐ์กด์— ์ง„ํ–‰ ์ค‘์ด๋˜ ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด ์ทจ์†Œํ•˜๊ณ , ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์œผ๋กœ ์‹คํ–‰๋œ ์ž‘์—…๋งŒ ์ˆ˜ํ–‰


```js
import { GET_POSTS, GET_REQ } from "../types";
import { all, fork, put, takeEvery } from "redux-saga/effects";

function* post() {
yield put({
type: GET_POSTS,
payload: ["1st post", "2nd posts", "3 posts"],
});
}

function* watchPost() {
yield takeEvery(GET_REQ, post);
}

//postSaga() ์—ฌ๋Ÿฌ Saga ํ†ตํ•ฉ
export default function* postSaga() {
yield all([fork(watchPost)]);
}

```

### ๐Ÿƒ reducers/index.js
- combineReducers: ๋งŽ์€ Reducer๋“ค์„ ํ•˜๋‚˜๋กœ ํ•ฉ์ณ ํ•˜๋‚˜์˜ Reducer๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด์ค€๋‹ค.


```js
import { combineReducers } from "redux";
import { postReducer } from "../reducers/postReducer";

export default combineReducers({
post: postReducer,
});

```


### ๐Ÿƒ reducers/postReducer.js
```js
import * as types from "../types";

const initialState = {
posts: [],
post: {},
loading: false,
error: null,
};

export const postReducer = (state = initialState, action) => {
switch (action.type) {
case types.GET_REQ:
return {
...state,
posts: [],
loading: true,
error: null,
};
case types.GET_POSTS:
return {
...state,
posts: action.payload,
loading: false,
error: null,
};
default:
return state;
}
};

```