A helper to handle REST Apis with Redux in react-native
react-native-redux-rest-resource
A helper to handle REST Apis with Redux in react-native.
How to set it up
// resources.js
import Resource from 'react-native-redux-rest-resource';
export const PostsResource = Resource(
'post',
{
API_URL: 'https://mygreat.api.com/v1/', // Define the URL of your API
HTTP_HEADERS: { X-MOBILE-TOKEN: 'j3rkl2uh44u4uys87w3874y3rt3487wrtyw87' }, // Set extra headers
}
);
// store.js
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import { Platform } from 'react-native';
import devTools from 'remote-redux-devtools';
import Thunk from 'redux-thunk';
import { PostsResource } from './resources';
import PostsReducer from './postsReducer';
const enhancer = compose(
applyMiddleware(Thunk, PostsResource.middleware),
devTools({
hostname: 'localhost',
port: 28000,
name: `MyAPP_${Platform.OS}`,
})
);
export default createStore(
combineReducers({
Posts: PostsReducer,
}),
enhancer
);
How to trigger RESTful Requests
// TestClass.js
import React, { Component } from 'react';
import {
ActivityIndicator,
StyleSheet,
Text,
View,
} from 'react-native';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { PostsResource } from './resources';
const styles = StyleSheet.create({
container: {}
});
class TestClass extends Component {
componentDidMount() {
this.props.index(); // Get all the posts
this.props.create({ content: 'Hello' }); // Create a post
setTimeout(() => this.props.read(this.props.posts[0].id), 5000); // Get a post
setTimeout(() => this.props.update({ content: 'Hello There!' }, 1), 10000); // Create a post
setTimeout(() => this.props.delete(1), 20000); // Delete the post of ID 1
}
render() {
return (
<View style={styles.container}>
{!this.props.loading && !this.props.error
? this.props.posts.map((post) => (
<View key={post.id}>
<Text>{post.content}</Text>
</View>
))
: null
}
{this.props.loading
? <ActivityIndicator />
: null
}
{this.props.error
? <Text>{this.props.error.message}</Text>
: null
}
</View>
);
}
}
const mapStateToProps = (state) => ({
posts: Object.values(state.Posts.List),
error: state.Posts.error,
loading: state.Posts.loading,
});
const mapDispatchToProps = (dispatch) => bindActionCreators(
PostsResource.actionCreators,
dispatch
);
export default connect(
mapStateToProps,
mapDispatchToProps
)(TestClass);
How to handle the result of the requests
// postsReducer.js
import PostsResource from './resources';
export default = (
state = {
List: {},
loading: false,
error: null,
},
action
) => {
switch (action.type) {
case PostsResource.actions.CREATE:
case PostsResource.actions.READ:
case PostsResource.actions.UPDATE:
case PostsResource.actions.DELETE:
case PostsResource.actions.INDEX:
return {
...state,
loading: true,
};
case PostsResource.actions.CREATE_SUCCESS:
case PostsResource.actions.READ_SUCCESS:
case PostsResource.actions.UPDATE_SUCCESS:
return {
...state,
List: {
...state.List,
[action.payload.id]: action.payload,
},
loading: false,
error: null,
};
case PostsResource.actions.DELETE_SUCCESS:
const updatedList = { ...state.List };
delete updatedList[action.meta.id];
return {
...state,
List: updatedList,
loading: false,
error: null,
};
case PostsResource.actions.INDEX_SUCCESS:
return {
...state,
List: {
...state.List,
...action.payload.reduce((accumulator, post) => {
accumulator[post.id] = post;
return accumulator;
}, {}),
},
loading: false,
error: null,
};
case PostsResource.actions.CREATE_FAILURE:
case PostsResource.actions.READ_FAILURE:
case PostsResource.actions.UPDATE_FAILURE:
case PostsResource.actions.DELETE_FAILURE:
case PostsResource.actions.INDEX_FAILURE:
return {
...state,
loading: false,
error: action.payload,
};
default:
return state;
}
};
Options
KEY | VALUE | DEFAULT VALUE | WHAT DOES IT DO |
---|---|---|---|
API_URL | URL | 'localhost/' |
The Base url of your API |
CAMELIZE_DECAMELIZE | true/false | true |
All the keys of objects coming in from the server will be camelized (ex: customer_id will be transformed to customerId ) and everything that goes out of the client will be decamelized (ex: customerId will be transformed to customer_id ) |
DEBUG | true/false | true |
console.log s stuff about what is happening network-wise |
HTTP_ERROR_CODE_MESSAGES | An object with keys being the status code and values being the messages | { 401: 'FORBIDDEN', 403: 'FORBIDDEN', 404: 'NOT_FOUND', } |
Customize the messages of the errors caught while doing the requests |
HTTP_HEADERS | Headers put on the requests | {} |
Headers to add to the requests |
JWT_TOKEN | YOUR_JWT_TOKEN | null |
This will add an Authorization header with value Bearer YOUR_JWT_TOKEN |
REDUX_ACTIONS_PREFIX | Prefix to add to actions type | 'RNRRR' | Namespaces actions to avoid conflicts with your actions |
TODO
- postfix actionCreators with appropriate
endpoint
camelized and pluralized term - Create Basic Reducer automatically?