Skip to content

Instantly share code, notes, and snippets.

@bootcoder
Last active November 5, 2018 19:16
Show Gist options
  • Save bootcoder/94ed3c73f54ff681fe8513874f50682e to your computer and use it in GitHub Desktop.
Save bootcoder/94ed3c73f54ff681fe8513874f50682e to your computer and use it in GitHub Desktop.
ReduxRootComponent Architecture
// ReduxRootComponent.tsx
import React from 'react'
import { Provider } from 'react-redux'
import WebpackerReact from 'webpacker-react'
import configureStore from '../store/configureStore'
const store = configureStore()
export function composeWithRedux (ReduxComponent, props) {
WebpackerReact.register(ReduxComponent.WrappedComponent)
return (
<Provider store={store}>
<ReduxComponent {...props} />
</Provider>
)
}
// SampleContainer.tsx - parent smart component which needs to connect to Redux
// This is the component which is rendered in the HAML.
// All rendered components which require state connect to Redux by composeWithRedux wrapper function.
import * as React from 'react';
import { composeWithRedux } from '../ReduxRootComponent';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import SampleCard from './SampleCard';
import * as sampleActions from '../../actions/sampleActions';
import * as userActions from '../../actions/userActions';
import './SampleContainer.scss';
import 'bootstrap/dist/css/bootstrap.css';
/* eslint-disable no-undef, no-unused-vars */
type SampleContainerProps = {
message?: string;
cards: any[];
actions: { [key: string]: any };
selectedCardId: number;
};
/* eslint-enable no-undef, no-unused-vars */
export class SampleContainer extends React.Component<SampleContainerProps> {
constructor (props?: any) {
super(props);
this.renderCards = this.renderCards.bind(this);
this.handleAddCard = this.handleAddCard.bind(this);
this.handleRemoveCard = this.handleRemoveCard.bind(this);
this.handleLikeCard = this.handleLikeCard.bind(this);
this.handleSelectCard = this.handleSelectCard.bind(this);
}
handleAddCard () {
this.props.actions.addCard();
}
handleLikeCard (cardId) {
this.props.actions.likeCard(cardId);
}
handleRemoveCard () {
this.props.actions.removeCard();
}
handleSelectCard (cardId) {
this.props.actions.selectCard(cardId);
}
renderCards () {
return this.props.cards.map((card, idx) => {
return (
<SampleCard
key={idx}
id={card.id}
value={card.value}
likesCount={card.likesCount}
handleLikeCard={this.handleLikeCard}
handleSelectCard={this.handleSelectCard}
selectedCardId={this.props.selectedCardId}
/>
);
});
}
render () {
return (
<div className='SampleContainer container'>
<div className='row'>
<h2>
SampleContainer Component Supreme!
</h2>
<p>Message: {this.props.message}</p>
<div className='btn-group'>
<button
className='btn btn-success handleAddCard'
onClick={this.handleAddCard}>
Add New Card!
</button>
<button
className='btn btn-warning handleRemoveCard'
onClick={this.handleRemoveCard}>
Remove Selected Card.
</button>
</div>
</div>
<div className='row'>{this.renderCards()}</div>
</div>
);
}
}
function mapDispatchToProps (dispatch) {
return {
actions: bindActionCreators(Object.assign({}, sampleActions, userActions), dispatch)
};
}
const mapStateToProps = state => {
return {
user: state.user.userPayload,
message: state.sample.message,
selectedCardId: state.sample.selectedCardId,
cards: state.sample.cardCollection
};
};
const comp = connect(
mapStateToProps,
mapDispatchToProps
)(SampleContainer);
let ReduxSampleContainer = props => composeWithRedux(comp, props);
export default ReduxSampleContainer;
// SampleContainer.test.tsx
import WebpackerReact from 'webpacker-react';
import * as React from 'react';
import { mount } from 'enzyme';
import SampleContainer from './SampleContainer';
import SampleCard from './SampleCard';
function setup () {
const comp = mount(<SampleContainer />);
console.log(comp);
debugger;
return comp;
}
describe('<SampleContainer />', () => {
let wrapper;
beforeEach(() => {
wrapper = setup();
});
afterEach(() => {
wrapper.unmount();
WebpackerReact.registeredComponents = {};
});
it('passes smoke test', () => {});
it('renders card components', () => {
expect(wrapper).toContainMatchingElements(1, 'SampleCard');
expect(wrapper.find(SampleCard).first()).toHaveProp('value');
expect(wrapper.find(SampleCard).first()).toHaveProp('id');
expect(wrapper.find(SampleCard).first()).toHaveProp('likesCount');
expect(wrapper.find(SampleCard).first()).toHaveProp('handleLikeCard');
expect(wrapper.find(SampleCard).first()).toHaveProp('handleSelectCard');
});
it('adds a new card', () => {
expect(wrapper).toContainMatchingElements(1, 'SampleCard');
wrapper.find('.handleAddCard').simulate('click');
expect(wrapper).toContainMatchingElements(2, 'SampleCard');
});
// Fails due to the Container state already having a SampleCard when test begins.
it('remove a card', () => {
expect(wrapper).toContainMatchingElements(1, 'SampleCard');
wrapper.find('.handleRemoveCard').simulate('click');
expect(wrapper).toContainMatchingElements(0, 'SampleCard');
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment