<구성>
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
const store = createStore(/*your root reducer*/);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
// App.js
export default function App() {
return (
<Player>
<ItemBox />
</Player>
)
}
// src/Redux/Actions/index.js
export const addMusic = (song) =>{
return {
type: "ADD_MUSIC",
payload: song
}
}
// src/Redux/Reducers/songList.js
export default function songList(state = initialState, action) {
switch (action.type) {
case "ADD_MUSIC":
return [...state, ...action.payload]
default:
return state;
}
};
// src/Redux/rootReducers.js
import { combineReducers } from "redux";
import songList from "Redux/Reducers/songList";
const rootReducer = combineReducers({
songList,
});
export default rootReducer;
// src/Components/ListBox.js
import { connect } from 'react-redux';
import { addMusic } from '../Redux/Actions';
const mapStateToProps = (state) => {
return {
songList: state.songList,
};
};
const mapDispatchToProps = (dispatch, ownProps) => {
return {
addMusic: (song) => {
dispatch(addMusic(song));
},
};
};
// mapStateToProps가 없으면 null 써주면 된다.
export default connect(mapStateToProps, { addMusic })(ListBox);
// export default connect(mapStateToProps, mapDispatchToProps)(ListBox);
<구성>
// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { StateProvider } from "./Store/store";
ReactDOM.render(
<React.StrictMode>
<StateProvider>
<App />
</StateProvider>
</React.StrictMode>,
document.getElementById("root")
);
// src/Store/store.js
import React, { createContext, useContext, useReducer } from "react";
const initialState = { count: 0};
const countContext = createContext(initialState);
const useCount = () => useContext(countContext);
const { Provider } = countContext;
const StateProvider = ({ children }) => {
const [state, dispatch] = useReducer((state, action) => {
switch (action.type) {
case "ADD_NUM":
return { count: state.count + action.payload}
default:
throw new Error();
}
}, initialState);
return <Provider value={[state, dispatch]}>{children}</Provider>;
};
export { StateProvider, useCount };
// App.js
import React from "react";
import "./App.css";
import Button from "./components/Button";
import { useCount } from "./Store/store";
const App = props => {
const [state] = useCount();
return (
<>
<div>{state.count}</div>
<Button></Button>
</>
);
};
export default App;
// AddCount 컴포넌트는 Button 컴포넌트의 자식 컴포넌트이다.
// src/components/AddCount
import React from "react";
import { useCount } from "../Store/store";
const AddCount = props => {
const [store, dispatch] = useCount();
const handleClick = () => {
dispatch({
type: "ADD_NUM",
payload: 1
});
};
return (
<div>
<button onClick={handleClick}>더하기 + 1</button>
</div>
);
};
export default AddCount;
const add = (a, b) => a + b; //pure function
Redux는 state가 불변해야 한다는 특징을 가지고 있다. 불변한다는 것은 state가 변경되면 안된다는 뜻이 아니라 state가 수정되면 안된다는 뜻이다.
state 값을 변경할때는 스프레드 연산자로 기존 state 값을 복사한 뒤 변경된 state를 반환한다. Redux는 reducer를 거친 state가 변경됐는지를 검사하기 위해 state 객체의 주소를 비교하는데 state의 복제본을 만들어 반환하면 이전의 state와 다른 주소값을 가르키기 때문에 state가 변경되었다고 판단한다. 반대로 state를 복제하는 것이 아닌 속성만 수정하여 반환하면 기존의 state 객체와 가리키는 주소값이 같이 때문에 변경감지가 되지 않는다.
그렇다면 왜 주소를 비교하는 걸까? 그 이유는 객체 속성을 비교하는 것은 깊은 비교라고 하는데 복잡하고 무거운 알고리즘이 필요하기 때문이다.