HOC that saves, loads and resets data extracted from the props in the tabState
reducer on tab switch.
returns a new, component class.
-
[
mapPropsToTabState(ownProps): tabState
] (Function): The returned component, while saving thetabState
, will callmapPropsToTabState
withownProps
. The results ofmapPropsToTabState
must be a plain object (serves as payload), which will be merged into thetabState
stored in the redux-store. Every time, thetabState
is picked up from the redux-store, the callbackonAction
( should be passed down as a prop ) will be called with{ type: 'VIEW_STATE_UPDATED', payload }
. -
[
options
] (Object) If specified, further customizes the behavior of the connector. It accepts these additional options:- [
tabStateName
] (String): Highly recommended to specify it. Used for making the key for storing the payload in the Redux's store state. - [
shouldStoreScroll
] (Boolean): When true, injects a functionsetScrollContainerRef
. Use it on the element for which you want to store the scroll position. It will take care of restoring the scroll position ( no callbacks needed ). If you want to just maintain the scroll position without saving any state, passmapPropsToTabState
asnull
orundefined
.
- [
class TodoList extends React.PureComponent {
state = { selectedTodoIds: {} };
handleAction = action => {
switch(action.type){
case 'TODO_SELECTED':
this.setState({
selectedTodoIds: {
...this.state.selectedTodoIds,
[action.payload.id] : true,
},
});
break;
default:
break;
}
}
render(){
return (
<div>
{this.props.todos.map(todo => (
<Todo
key={todo.id}
todo={todo}
selected={this.state.selectedTodoIds[todo.id]}
onAction={this.handleAction}
/>
)}
</div>
);
}
}
We want to store the selectedTodoIds
, on switching the tab and get it back on switching back to the tab.
Solution 1
- Make
TodoListContainer
. - Pass down the entire state.
- Pass down
onAction
.
class TodoListContainer extends React.PureComponent {
state = { selectedTodoIds: {} };
handleAction = action => {
switch(action.type){
case 'TODO_SELECTED':
this.setState({
selectedTodoIds: {
...this.state.selectedTodoIds,
[action.payload.id] : true,
},
});
break;
case 'VIEW_STATE_UPDATED':
this.setState(action.payload);
break;
default:
break;
}
}
render(){
return (
<TodoList {...this.props} {...this.state} onAction={this.handleAction} />
);
}
}
TodoList.js
const TodoList = props => (
<div>
{props.todos.map(todo => (
<Todo
key={todo.id}
todo={todo}
selected={props.selectedTodoIds[todo.id]}
onAction={props.onAction}
/>
)}
);
const mapPropsToTabState = props => _pick(props, 'selectedTodoIds');
export default withTabState(mapPropsToTabState, {tabStateName: 'TodoList'} )(TodoList);
Solution 2
- Use
connectActionsAndTabState
todoListHandlers.js
export default {
TODO_SELECTED(action, {getState, setState}) {
setState({
selectedTodoIds: {
...(getState().selectedTodoIds || {}),
[action.payload.id] : true,
},
});
},
}
TodoList.js
const TodoList = props => (
<div>
{props.todos.map(todo => (
<Todo
key={todo.id}
todo={todo}
selected={props.selectedTodoIds[todo.id]}
onAction={props.onAction}
/>
)}
</div>
);
TodoList.defaultProps = { selectedTodoIds: {} };
const mapPropsToTabState = props => _pick(props, 'selectedTodoIds');
export default compose(
connectActionsWithTabState(todoListActionHandlers),
withTabState(mapPropsToTabState, {tabStateName: 'TodoList'} )
)(TodoList);
class MyScrollableComponent extends React.PureComponent {
render(){
return (
<div className="ovf-y-auto" ref={this.props.setScrollContainerRef}>
{this.renderContent()}
</div>
);
}
}
export default withTabState(null, {
tabStateName: 'MyScrollableComponent',
shouldStoreScroll: true,
})(MyScrollableComponent);