import { legacy_createStore as createStore } from 'redux';
import { composeWithDevTools } from '@redux-devtools/extension';
import counterReducer from './reducers/counterReducer';
const store = createStore(counterReducer, composeWithDevTools());
export default store;
Com combineReducers
import { combineReducers } from 'redux';
import { legacy_createStore as createStore } from 'redux';
import { composeWithDevTools } from '@redux-devtools/extension';
import counterReducer from './reducers/counterReducer';
import userReducer from './reducers/userReducer';
const rootReducer = combineReducers({
counter: counterReducer,
user: userReducer,
});
const store = createStore(rootReducer, composeWithDevTools());
export default store;
Em aplicações maiores, cada reducer deve ficar em um arquivo separado
Neste caso, criamos o arquivo src/redux/reducers/counterReducer.js
implementação mais simples do reducer
// const INITIAL_STATE = { count: 0 };
// const reducer = (state = INITIAL_STATE, action) => state;
// const store = createStore(reducer, composeWithDevTools());
Implementação do reducer com ação
const INITIAL_STATE = {
count: 0,
};
// function reducer(state = INITIAL_STATE, action) {
function counterReducer(state = INITIAL_STATE, action) {
switch (action.type) {
case 'INCREMENT_COUNTER':
// return { count: state.count + 1 };
return { count: state.count + action.payload };
default:
return state;
}
}
export default counterReducer;
Tratando com a imutabilidade do estado global
const INITIAL_STATE = {
clicks: 0,
count: 0,
};
function counterReducer(state = INITIAL_STATE, action) {
switch (action.type) {
case 'INCREMENT_COUNTER':
return {
...state,
count: state.count + action.payload,
};
default:
return state;
}
}
export default counterReducer;
const INITIAL_STATE = {
clicks: 0,
count: 0,
};
// Estado global com combineReducers:
state = {
counterReducer: {
count: 0,
clicks: 0,
}
}
// Estado global sem combineReducers:
state = {
count: 0,
clicks: 0,
}
function counterReducer(state = INITIAL_STATE, action) {
switch (action.type) {
case 'INCREMENT_COUNTER':
return {
...state,
count: state.count + action.payload,
};
case 'INCREMENT_CLICK':
return {
...state,
clicks: state.clicks + 1,
};
default:
return state;
}
}
export default counterReducer;
- Faz a ponte entre as bibliotecas do React e do Redux
- envolve a aplicação com o provider
- passa a store como propriedade
import { Provider } from 'react-redux';
import store from './redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={ store }>
<App />
</Provider>,
);
- conecta o componente com o estado do redux
- passa o estado e as ações como propriedades
import { connect } from 'react-redux';
export default connect(mapStateToProps)(App);
- mapeia o estado para as propriedades do componente
const mapStateToProps = (state) => ({
countState: state.count,
});
Com combineReducers
const mapStateToProps = (state) => ({
countState: state.counterReducer.count,
});
Action é um objeto que descreve o que deve ser feito
- cria as ações
export const action = {
type: 'INCREMENT'
}
padrão mais comum é criar uma função que retorna o objeto e chamar essa função de action creator, isso possibilita a passagem de parâmetros para a action como no exemplo abaixo com o payload.
export const actionCreator = () => {
return {
type: 'INCREMENT'
}
}
podemos passar parâmetros para a actionCreator
export const actionCreator = (increment = 1) => ({
type: 'INCREMENT_COUNTER',
payload: increment,
});
-
importa a actionCreator
-
passa a actionCreator como propriedade do componente
-
chama a actionCreator no componente
-
exemplo 1:
import React from 'react';
import { connect } from 'react-redux';
import { actionCreator } from './redux/actions';
// function App(props) {
class App extends React.Component {
render() {
// const { countState } = this.props;
const { dispatch, countState } = this.props;
return (
<div>
<h1>Contador</h1>
<h2>{ countState }</h2>
{/* <button>Incrementa 1</button>
<button>Incrementa 5</button> */}
<button onClick={() => dispatch(actionCreator())}>Incrementa 1</button>
<button onClick={() => dispatch(actionCreator(5))}>Incrementa 5</button>
</div>
);
}
}
// mapeia o estado para props
// { prop: value} -> props do componente App e o valor que está no estado
const mapStateToProps = (state) => ({
countState: state.count,
});
// export default App;
export default connect(mapStateToProps)(App);
- exemplo 2:
import React from 'react';
import { connect } from 'react-redux';
import { actionCreator } from './redux/actions';
// funcional
// const App = ({ incrementCount, countState }) => {
// return (
// classe
class App extends React.Component {
render() {
const { incrementCount, countState } = this.props;
return (
<div>
<h1>Contador</h1>
<h2>{ countState }</h2>
<button onClick={() => incrementCount(1)}>Incrementa 1</button>
<button onClick={() => incrementCount(5)}>Incrementa 5</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
countState: state.count,
});
const mapDispatchToProps = (dispatch) => ({
incrementCount: (value) => dispatch(actionCreator(value)),
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
- cria o reducer
- cria o arquivo de actions
- cria o arquivo de actionCreators
- importa o reducer no arquivo
src/redux/index.js
- cria o combineReducers
- passa o combineReducers para o createStore
import { combineReducers } from 'redux';
import counterReducer from './reducers/counterReducer';
import userReducer from './reducers/userReducer';
const rootReducer = combineReducers({
counter: counterReducer,
user: userReducer,
});
// Estado global com combineReducers:
state = {
counterReducer: {
count: 0,
clicks: 0,
}
}
// Estado global sem combineReducers:
state = {
count: 0,
clicks: 0,
}
const mapStateToProps = (state) => ({
countState: state.counterReducer.count,
});