Hi! Welcome to the last part of blog series about debouncing forms in React. Today I want to show you how can you add redux to your debounced component.
Adding redux
It may seem like overkill for this simple example but I decided to add redux to show how this debounced form can be used in the more realistic scenario.
So, after adding redux and react-redux to my application I started by creating actions & actions
creators under src/actions/index.js:
export const ADD_WORD = 'ADD_WORD';
export const addWord = (word) => ({
type: ADD_WORD,
word,
});To explain how those two can be used I added a small test in ‘actions.test.js`:
import { ADD_WORD, addWord } from './index';
describe('Actions', () => {
it('should create action to add word', () => {
const expectedAction = {
type: ADD_WORD,
word: 'fake',
};
expect(addWord('fake')).toEqual(expectedAction);
});
});As you can see calling addWord with some string should dispatch action with ADD_WORD type and typed
a word.
Next step was to add src/reducers/index.js:
import { combineReducers } from 'redux';
import { ADD_WORD } from '../actions/index';
export const words = (state = [], action) => {
switch (action.type) {
case ADD_WORD:
return [action.word, ...state];
default:
return state;
}
};
const rootReducer = combineReducers({ words });
export default rootReducer;Where I have my pure function words which is getting its own piece of state to work with. In this
case, I want my typed words to be first in a state of my application. I also added tests:
import { words } from './index';
import { ADD_WORD } from '../actions/index';
describe('Words reducer', () => {
it('should return initial state', () => {
expect(words(undefined, {})).toEqual([]);
});
it('should handle ADD_WORD on initial state', () => {
expect(words([], { type: ADD_WORD, word: 'tom' })).toEqual(['tom']);
});
it('should handle ADD_WORD on existing state', () => {
expect(words(['tim'], { type: ADD_WORD, word: 'tom' })).toEqual(['tom', 'tim']);
});
});The last thing is to set up my store and connect it with react application. The first step is happening in
store.js:
import { createStore, compose } from 'redux';
import rootReducer from './reducers';
const store = createStore(
rootReducer,
compose(window.devToolsExtension ? window.devToolsExtension() : (f) => f)
);
export default store;I create here my store with rootReducer which in this case is just only words reducer and I also
added redux dev tools which help me debug my redux code.
The second step is to modify my index.js so redux can be injected into my application:
import { Provider } from 'react-redux';
import AppContainer from './components/App/AppContainer';
import store from './store';
const root = (
<Provider store={store}>
<AppContainer />
</Provider>
);
ReactDOM.render(root, document.getElementById('root'));Using redux with react applications
You may notice that Provider component is wrapping a new one - AppContainer. This is a nice pattern
to use when using redux & react applications. It boils down to two concepts: component and container.
A component is responsible only for rendering html. A container is a way to get your data from the redux store.
That’s why I created AppContainer:
import React from 'react';
import { connect } from 'react-redux';
import { addWord } from '../../actions/index';
import App from './App';
export const AppContainer = (props) => <App addWord={props.addWord} words={props.words} />;
const mapDispatchToProps = (dispatch) => ({
addWord: (word) => dispatch(addWord(word)),
});
const mapStateToProps = (state) => ({
words: state.words,
});
export default connect(mapStateToProps, mapDispatchToProps)(AppContainer);Here I added two typical functions for react applications with redux - mapDispatchToProps &
mapStateToProps. In the first one, I tell redux that when I call addWord inside my App component
it should dispatch an action from actions/index. The second function is for extracting the data from
the store - it will be the best if my component has only access to this part of a state which it is
concerned about.
That’s all for today! To recap: I’ve added redux to my application and used Presentational and Container Components and I have my debounced input with react & redux!
Github repo can be found here.