React-Native SwitchNavigator don't provide new props in root - react-native

I have problem with receiving new props in root stack navigator. I have 2 screens in stack navigator: list and edit item. On list screen i click a edit button and dispatch data to store - it works. But in the edit screen i edit data and dispatch new list with new element (for test). List screen dont receive new list. Can you help me?
App.js
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'CATEGORIES_CHANGED':
return {
...state,
categories: action.data
};
case 'SET_CATEGORY_INFO':
return {
...state,
categoryInfo: action.data
};
default:
return state;
}
};
const store = createStore(reducer);
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppNavigator/>
</Provider>
);
}
}
AppNavigator.js
import React from 'react';
import { createSwitchNavigator } from 'react-navigation';
import MainTabNavigator from './MainTabNavigator';
import { connect } from 'react-redux';
const AppNavigator = createSwitchNavigator({
Main: MainTabNavigator
});
export default AppNavigator;
MainTabNavigator.js
import React from 'react';
import {Platform} from 'react-native';
import {createStackNavigator, createBottomTabNavigator} from 'react-navigation';
import { connect } from 'react-redux';
...
const CategoriesStack = createStackNavigator({
CategoriesListScreen: {
screen: CategoriesListScreen,
},
CategoryInfoScreen: {
screen: CategoryInfoScreen,
},
CategoryEditScreen: {
screen: CategoryEditScreen,
},
});
CategoriesStack.navigationOptions = {
tabBarLabel: 'Categories',
tabBarIcon: ({focused}) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? 'ios-link' : 'md-link'}
/>
),
};
...
const bottomTabNavigator = createBottomTabNavigator({
CategoriesStack,
...
});
export default bottomTabNavigator;
CategoriesListScreen.js
import { connect } from 'react-redux';
class CategoriesListScreen extends React.Component {
render() {
const cats = this.state.categories;
return (
<ScrollView style={styles.container}>
{cats.map((category, i) => {
return (
<TouchableOpacity key={category.id} style={
(i === cats.length - 1) ?
{...styles.categoryItem, ...styles.categoryItemLast} :
styles.categoryItem
} onPress={()=>{this.onPressCategory(category)}}>
<View style={{
...styles.categoryLabel, ...{
backgroundColor: category.color
}
}}>
<Icon name={category.icon} size={25} style={styles.categoryIcon}
color={category.iconColor}/>
</View>
<Text>{category.title}</Text>
</TouchableOpacity>
)
})}
</ScrollView>
);
}
componentWillReceiveProps(nextProps) {
console.log(nextProps);
}
componentWillMount() {
const categories = this.props.categories;
this.setState({
categories: categories
});
}
onPressCategory(category) {
this.props.setCategoryInfo(category);
this.props.navigation.navigate('CategoryInfoScreen', {});
}
}
function mapStateToProps(state) {
return {
categories: state.categories
}
}
function mapDispatchToProps(dispatch) {
return {
setCategoryInfo: (category) => dispatch({ type: 'SET_CATEGORY_INFO', data: category })
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CategoriesListScreen)
CategoryEditScreen.js
import { connect } from 'react-redux';
class CategoryEditScreen extends React.Component {
static navigationOptions = ({navigation}) => {
return {
title: 'Edit Category',
headerRight: <Button onPress={() => {navigation.getParam('categoryChangedDispatch')()}} title="Save"/>
}
};
render() {
const category = this.state.category;
...
}
componentWillMount() {
const category = this.props.categoryInfo;
this.setState({
category: category
});
}
componentDidMount() {
this.props.navigation.setParams({
categoryChangedDispatch: this.categoryChangedDispatch.bind(this)
});
}
categoryChangedDispatch() {
let cats = this.props.categories;
cats.push({
id: 3,
title: 'My third category',
color: '#7495e7',
icon: 'airplane',
iconColor: '#2980B9'
});
this.props.categoryChanged(cats);
this.props.navigation.navigate('CategoryInfoScreen', {});
}
}
function mapStateToProps(state) {
return {
categories: state.categories,
categoryInfo: state.categoryInfo
}
}
function mapDispatchToProps(dispatch) {
return {
categoryChanged: (categories) => dispatch({ type: 'CATEGORIES_CHANGED', data: categories }),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CategoryEditScreen)

It seems it's related to the fact you update your local state (this.state.categories) based on the categories property, only during the componentWillMount phase but not when props are updated (which should happen after you dispatched the new data).
Try using this.props.categories directly within your CategoriesListScreen component.

before
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'CATEGORIES_CHANGED':
return {
...state,
categories: action.data
};
default:
return state;
}
};
after
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'CATEGORIES_CHANGED':
return {
...state,
categories: Object.assign([], action.data)
};
default:
return state;
}
};
Reducer has problem. I made the absolutely new array. It works! But I think it isn't normal :)

Related

React navigation and loading component in react native

Hello I have a react component like which either display a list of items or opens another component which allowes me to select some value. Here is the code
import React, { PureComponent } from "react";
import { Text, View } from "react-native";
import { withNavigationFocus } from "react-navigation-is-focused-hoc";
import { NavigationActions } from "react-navigation";
import { connect } from "react-redux";
import ClassListing from '../../components/ClassListing/ClassListing';
import Actions from "../../state/Actions";
import { default as stackStyles } from "./styles";
import {
StyleCreator
} from "../../utils";
let styles = StyleCreator(stackStyles.IndexStyles)();
#withNavigationFocus
#connect(() => mapStateToProps, () => mapDispatchToProps)
export default class ClassList extends PureComponent {
static navigationOptions = ({ navigation }) => {
const { params } = navigation.state;
return {
header: null,
tabBarOnPress({ jumpToIndex, scene }) {
params.onTabFocus();
jumpToIndex(scene.index);
},
};
};
constructor(props) {
super(props);
this.state = {};
console.ignoredYellowBox = ["Warning: In next release", "FlatList"];
}
componentDidMount() {
console.log("componentDidMount");
this.props.navigation.setParams({
onTabFocus: this.handleTabFocus
});
}
componentDidUpdate() {
console.log("I am updated");
}
_handleNavigationBar = () => (
<View style={styles.headerContainer}>
<Text style={styles.headerLeftTitle}>Klasselister</Text>
</View>
);
handleTabFocus = () => {
this.props.resetClassList();
// setTimeout(() => {
// this._openChildSchoolSelector();
// },500);
};
_openChildSchoolSelector = () => {
if (
!this.props.childrenSelection.selectedDependant ||
!this.props.childrenSelection.selectedSchool
) {
console.log("navigate to child selector");
this.props.navigation.dispatch(
NavigationActions.navigate({
routeName: "ChildSchoolSelector",
})
);
}
};
render() {
return (
<View>
{this._handleNavigationBar()}
{this.props.classList &&
this.props.classList.classList &&
this.props.classList.classList.length > 0 ? (
<ClassListing list={this.props.classList.classList} />
) : (
null
// this._openChildSchoolSelector()
)}
</View>
);
}
}
const mapStateToProps = (state) => {
const { classList, childrenSelection } = state.appData;
console.log("[Classlist] mapStateToProps", classList);
console.log("[Classlist] mapStateToProps", childrenSelection);
return {
classList,
childrenSelection
};
};
const mapDispatchToProps = (dispatch) => ({
resetClassList: () => {
dispatch(Actions.resetClassList());
},
});
My issue is that when I come to this tab, I want to reset the list which came from server and then open the school selector again, which I am doing in handleTabFocus. But there I have to first call
this.props.resetClassList();
this._openChildSchoolSelector()
The issue is that this._openChildSchoolSelector() is called while this.props.resetClassList() hasn't fininshed.
this.props.resetClassList() works like this
it calls an action like this
static resetClassList() {
return {
type: ActionTypes.RESET_CLASS_LIST
};
}
which then cleans the classlist like this
case ActionTypes.RESET_CLASS_LIST:
return createDefaultState();
in ClassListReducer.js
and also in ChildrenSelectionRedcuer.js
case ActionTypes.RESET_CLASS_LIST:
return createDefaultState();
Any hints to solve this? My project uses very old React navigation v1
One thing which I did was to use this
componentWillReceiveProps(nextProps) {
console.log(this.props);
console.log(nextProps);
if (
nextProps.isFocused &&
nextProps.focusedRouteKey == "ClassList" &&
(!nextProps.childrenSelection.selectedDependant ||
!nextProps.childrenSelection.selectedSchool)
) {
console.log("componentWillReceiveProps");
this._openChildSchoolSelector();
}
if (
this.props.isFocused &&
this.props.focusedRouteKey === "ClassList" &&
nextProps.focusedRouteKey !== "ClassList"
) {
console.log("reset");
this.props.resetClassList();
}
}
But not sure if this is an elegant way of doing this

How to use AsyncStorage in createBottomTabNavigator with React Navigation?

I work with react-navigation v3 and I want to use AsyncStorage in createBottomTabNavigator for checking if user logged.
I save key to Stoage in LoginScreen:
await AsyncStorage.setItem('#MyStorage:isLogged', isLogged);
And I want to use AsyncStorage in my stack (TabStack):
const TabStack = createBottomTabNavigator(
{
Home: { screen: HomeScreen, },
// I need isLogged key from AsyncStorage here!
...(false ? {
Account: { screen: AccountScreen, }
} : {
Login: { screen: LoginScreen, }
}),
},
{
initialRouteName: 'Home',
}
);
How I can do it?
My environment:
react-native: 0.58.5
react-navigation: 3.3.2
The solution is: create a new component AppTabBar and set this in tabBarComponent property
const TabStack = createBottomTabNavigator({
Home: { screen: HomeScreen, },
Account: { screen: AccountScreen, }
},
{
initialRouteName: 'Home',
tabBarComponent: AppTabBar, // Here
});
And AppTabBar component:
export default class AppTabBar extends Component {
constructor(props) {
super(props);
this.state = {
isLogged: '0',
};
}
componentDidMount() {
this._retrieveData();
}
_retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('isLogged');
if (value !== null) {
this.setState({
isLogged: value,
});
}
} catch (error) {
// Error retrieving data
}
};
render() {
const { navigation, appState } = this.props;
const routes = navigation.state.routes;
const { isLogged } = this.state;
return (
<View style={styles.container}>
{routes.map((route, index) => {
if (isLogged === '1' && route.routeName === 'Login') {
return null;
}
if (isLogged === '0' && route.routeName === 'Account') {
return null;
}
return (
<View /> // here your tabbar component
);
})}
</View>
);
}
navigationHandler = name => {
const { navigation } = this.props;
navigation.navigate(name);
};
}
You don't need to do that, just may want to check for a valid session in the login screen.
You need to create 2 stacks, one for the auth screens and your TabStack for logged users:
const TabStack = createBottomTabNavigator({
Home: { screen: HomeScreen, },
Account: { screen: AccountScreen, }
},
{
initialRouteName: 'Home',
headerMode: 'none',
navigationOptions: {
headerVisible: false,
}
});
const stack = createStackNavigator({
Home: {screen: TabStack},
Login: { screen: LoginScreen, }
});
and then check for a valid session in LoginScreen in the method componentDidMount.
class LoginScreen extends Component {
componentDidMount(){
const session = await AsyncStorage.getItem('session');
if (session.isValid) {
this.props.navigate('home')
}
}
}
In your Loading screen, read your login state from AsyncStorage, and store it in your Redux store, ( or any sort of global data sharing mechanism of your choice ) - I'm using redux here, then read this piece of data in your Stack component like the following:
import React from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { createStackNavigator } from "react-navigation";
class Stack extends React.Component {
render() {
const { isLoggedIn } = this.props.auth;
const RouteConfigs = {
Home: () => (
<View>
<Text>Home</Text>
</View>
),
Login: () => (
<View>
<Text>Login</Text>
</View>
)
};
const RouteConfigs_LoggedIn = {
Home: () => (
<View>
<Text>Home</Text>
</View>
),
Account: () => (
<View>
<Text>Account</Text>
</View>
)
};
const NavigatorConfig = { initialRouteName: "Login" };
const MyStack = createStackNavigator(
isLoggedIn ? RouteConfigs_LoggedIn : RouteConfigs,
NavigatorConfig
);
return <MyStack />;
}
}
const mapStateToProps = ({ auth }) => ({ auth });
export default connect(mapStateToProps)(Stack);

Unrecognized font family 'entypo'

I'm using the create react native app by the expo team to build an app. Using Icon component from react-native-elements to create a react navigation header feature. Snippet below:
const Navigator = new createStackNavigator({
Home: {
screen: Home,
path: '/',
navigationOptions: ({ navigation }) => ({
title: 'Home',
headerStyle: {
backgroundColor: 'black'
},
headerLeft: (
<Icon
name="menu"
size={30}
type="entypo"
style={{ paddingLeft: 10 }}
/>
),
}),
},
})
I encountered this error:
After numerous iterations, I found this supposed work around 1st and 2nd by the expo team and implemented it this way below for the app but still encountering the same problems.
import Expo from "expo";
import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { AppLoading, Asset, Font } from 'expo';
import { FontAwesome, Ionicons } from '#expo/vector-icons';
import { connect } from 'react-redux'
import { Auth } from 'aws-amplify';
import AuthTabs from './auth/Tabs';
import Nav from './navs/Navigator';
import Home from "./components/Home";
class App extends React.Component {
state = {
user: {},
isLoading: true,
isLoadingComplete: false,
};
async componentDidMount() {
StatusBar.setHidden(true)
try {
const user = await Auth.currentAuthenticatedUser()
this.setState({ user, isLoading: false })
} catch (err) {
this.setState({ isLoading: false })
}
}
async componentWillReceiveProps(nextProps) {
try {
const user = await Auth.currentAuthenticatedUser()
this.setState({ user })
} catch (err) {
this.setState({ user: {} })
}
}
render() {
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return(
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
}
else{
if (this.state.isLoading) return null
let loggedIn = false
if (this.state.user.username) {
loggedIn = true
}
if (loggedIn) {
return (
<Nav />
)
}
return (
<AuthTabs />
)
}
}
_loadResourcesAsync = async () => {
console.log("fonts loading..")
const entypoFont = {
'entypo': require('../node_modules/#expo/vector-icons/fonts/Entypo.ttf')
};
const fontAssets = cacheFonts([ FontAwesome.font, Ionicons.font, entypoFont ]);
console.log("loaded all fonts locally")
await Promise.all([...fontAssets]);
console.log("promisified all fonts")
};
_handleLoadingError = error => {
console.warn(error);
};
_handleFinishLoading = () => {
this.setState({ isLoadingComplete: true });
};
}
function cacheFonts(fonts){
return fonts.map(font => Font.loadAsync(font))
}
const mapStateToProps = state => ({
auth: state.auth
})
export default connect(mapStateToProps)(App)
What are my doing wrong and how can it be configured appropriately? Thank you

React-Native/React navigation redirection after login with redux

I have a problem during the login my redirection is not done, I use a rail API for the back, I can recover the user, but when I click on login the page reloads and does not navigate on the home screen.
In my AuthActions.js after the dispatch I added NavigationActions.navigate ('Home'), this should allow me to go to the home page
AppNavigator.js
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { addNavigationHelpers, StackNavigator, TabNavigator } from 'react-navigation';
import { addListener } from '../../utils/redux';
import LoginScreen from '../login/LoginForm';
import RegisterScreen from '../register/RegisterForm';
import LogoutScreen from '../logout/Logout';
import Home from '../home/HomeList';
import Hair from '../hair/HairList';
export const Tabs = TabNavigator({
screen1: {
screen: Home
}
});
export const AppNavigator = StackNavigator({
Login: { screen: LoginScreen },
Main: { screen: Home },
Hair: { screen: Hair },
},{
initialRouteName : 'Login'
});
class AppWithNavigationState extends React.Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
nav: PropTypes.object.isRequired,
};
render() {
const { dispatch, nav } = this.props;
return (
<AppNavigator
navigation={addNavigationHelpers({
dispatch,
state: nav,
addListener,
})}
/>
);
}
}
const mapStateToProps = state => ({
nav: state.nav,
});
export default connect(mapStateToProps)(AppWithNavigationState);
AuthReducers.js
import {
EMAIL_CHANGED,
PASSWORD_CHANGED,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAIL,
LOGIN_USER
} from '../actions/types';
const INITIAL_STATE = {
email: '',
password: '',
user: null,
error: '',
loading: false,
};
export default (state = INITIAL_STATE, action) => {
// console.log('action =>', action);
switch (action.type) {
case EMAIL_CHANGED:
return { ...state, email: action.payload };
case PASSWORD_CHANGED:
return { ...state, password: action.payload };
case LOGIN_USER:
return { ...state, loading: true, error: '' };
case LOGIN_USER_SUCCESS:
return { ...state, ...INITIAL_STATE, user: action.payload };
case LOGIN_USER_FAIL:
return { ...state, error: 'Authentication Failed.', password: '', loading: false };
default:
return state;
}
};
// newState === oldState ? nothing : update state, so component too
AuthActions.js
import { NavigationActions } from 'react-navigation';
import Api from '../api';
import User from '../models/User';
import {
EMAIL_CHANGED,
PASSWORD_CHANGED,
LOGIN_USER_SUCCESS,
LOGIN_USER_FAIL,
LOGIN_USER
} from './types';
export const emailChanged = (text) => {
return {
type: EMAIL_CHANGED,
payload: text
};
};
export const passwordChanged = (text) => {
return {
type: PASSWORD_CHANGED,
payload: text
};
};
export const loginUser = ({ email, password }) => {
return (dispatch) => {
dispatch({ type: LOGIN_USER });
Api.userSignUp(email, password)
.then((user) => loginUserSuccess(dispatch, user))
.catch((error) => {
console.log(error);
loginUserFail(dispatch);
});
};
};
const loginUserFail = (dispatch) => {
dispatch({
type: LOGIN_USER_FAIL
});
};
const loginUserSuccess = (dispatch, user) => {
// console.log('access token =>', User.getAccessToken());
// Api.createEmployee(null);
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user,
});
NavigationActions.navigate('home'); //HERE NOT REDIRECT AFTER SUCCESS TO HOME
};
LoginForm.js
import React, { Component } from 'react';
import { Text } from 'react-native';
import { connect } from 'react-redux';
import { emailChanged, passwordChanged, loginUser } from '../../actions';
import { Card, CardSection, Input, Button, Spinner } from '../common';
class LoginForm extends Component {
onEmailChange(text) {
this.props.emailChanged(text);
}
onPasswordChange(text) {
this.props.passwordChanged(text);
}
onButtonPress() {
const { email, password } = this.props;
this.props.loginUser({ email, password });
}
renderButton() {
if (this.props.loading) {
return <Spinner size="large" />;
}
return (
<Button onPress={this.onButtonPress.bind(this)}>
Login
</Button>
);
}
render() {
return (
<Card>
<CardSection>
<Input
label="Email"
placeholder="email#gmail.com"
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
/>
</CardSection>
<CardSection>
<Input
secureTextEntry
label="Password"
placeholder="password"
onChangeText={this.onPasswordChange.bind(this)}
value={this.props.password}
/>
</CardSection>
<Text style={styles.errorTextStyle}>
{this.props.error}
</Text>
<CardSection>
{this.renderButton()}
</CardSection>
</Card>
);
}
}
const styles = {
errorTextStyle: {
fontSize: 20,
alignSelf: 'center',
color: 'red'
}
};
const mapStateToProps = ({ auth }) => {
const { email, password, error, loading } = auth;
return { email, password, error, loading };
};
export default connect(mapStateToProps, {
emailChanged, passwordChanged, loginUser
})(LoginForm);
App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import AppReducer from './reducers';
import AppWithNavigationState from './components/navigator/AppNavigator';
import { middleware } from './utils/redux';
import User from './models/User.js';
import {
NavigationActions,
} from 'react-navigation';
const store = createStore(
AppReducer,
applyMiddleware(ReduxThunk),
);
class App extends Component {
state = { isLoggedIn: null }
componentWillMount() {
// Si le asyncstorage a changé (connexion, etc)
User.getCurrent().then((user) => {
console.log('GetCurrentUser =>', user);
if (user) {
this.setState({isLoggedIn: true});
this.props.navigation.navigate('Main', user);
}
else {
this.setState({isLoggedIn: false});
}
})
}
render() {
return (
<Provider store={store}>
<AppWithNavigationState />
</Provider>
);
}
}
export default App;
I'm blocking for some day on the worries, I still is not finding a solution
use this code NavigationActions.NAVIGATE("home") works for me
You have to use componentWillReceiveProps in your Home like this:
//Home
componentWillReceiveProps(nextProps) {
if(nextProps.user) {
this.props.navigation.navigate('Home');
}
}
LoginForm.js
const mapStateToProps = state => {
return {
error: state.auth.error,
loading: state.auth.loading,
user: state.auth.user,
}
}
And you edit your AuthReducers.js like this:
case LOGIN_USER_SUCCESS:
return { ...state, ...INITIAL_STATE, user: action.user};
It works for me!

React native - Can't dispatch action in component because state gets undefined

In my react native android app, when I try to dispatch an action in BoardsScreen or in the root of the app, the following error pops up:
However, when I remove it, the app doesn't crashes.
BoardsScreen.js
import React from 'react';
import { connect } from 'react-redux';
import { Container, Content, Text, List, Button, Icon, ListItem } from 'native-base';
import { ListView, StatusBar } from 'react-native';
import { ConfirmDialog } from 'react-native-simple-dialogs';
import ActionButton from 'react-native-action-button';
import { removeBoard } from '../actions/configurationActions';
class BoardsScreen extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
boardDeleteDialog: false,
secId: null,
rowId: null,
rowMap: null,
};
}
deleteRow(secId, rowId, rowMap) {
rowMap[`${secId}${rowId}`].props.closeRow();
const newData = [...this.props.boards];
newData.splice(rowId, 1);
this.props.removeBoard(newData);
this.setState({
rowId: null,
secId: null,
rowMap: null,
boardDeleteDialog: false,
});
}
dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
render() {
console.log(this.props.boards);
return (
<Container>
<StatusBar backgroundColor="#00C853" />
<ConfirmDialog
title="Delete board?"
animationType="fade"
visible={this.state.boardDeleteDialog}
positiveButton={{
title: 'Delete',
titleStyle: {
color: '#2ecc71',
},
onPress: () => this.deleteRow(this.state.secId, this.state.rowId, this.state.rowMap),
}}
negativeButton={{
titleStyle: {
color: '#2ecc71',
},
title: 'Cancel',
onPress: () =>
this.setState({
boardDeleteDialog: false,
secId: null,
rowId: null,
rowMap: null,
}),
}}
/>
<Content>
{this.props.boards.length >= 1 ? (
<List
style={{ backgroundColor: '#D9534F' }}
dataSource={this.dataSource.cloneWithRows(this.props.boards)}
renderRow={data => (
<ListItem
style={{ paddingLeft: 14, backgroundColor: 'transparent' }}
button
onPress={() =>
this.props.navigation.navigate('Board', {
board: data.board,
boardName: data.boardName,
})
}
>
<Text>{data.boardName}</Text>
</ListItem>
)}
renderRightHiddenRow={(data, secId, rowId, rowMap) => (
<Button
full
danger
onPress={() =>
this.setState({
boardDeleteDialog: true,
secId,
rowId,
rowMap,
})
}
>
<Icon active name="trash" />
</Button>
)}
disableRightSwipe
rightOpenValue={-75}
/>
) : (
<Text>No boards added.</Text>
)}
</Content>
<ActionButton
buttonColor="#2ecc71"
fixNativeFeedbackRadius
onPress={() => this.props.navigation.navigate('AddBoard')}
/>
</Container>
);
}
}
const mapStateToProps = state => ({
boards: state.configurationReducer.boards,
});
const mapDispatchToProps = dispatch => ({
removeBoard: (board) => {
dispatch(removeBoard(board));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(BoardsScreen);
App.js
import React from 'react';
import { connect } from 'react-redux';
import MainNavigator from './src/config/Router';
import { addBoardToList } from './src/actions/configurationActions';
import { Board } from './src/API';
class App extends React.PureComponent {
componentDidMount() {
Board.getList(true).then(response => this.parseDataFromJSONResponse(response));
}
parseDataFromJSONResponse(response) {
for (let i = 0; i < response.length; i += 1) {
this.props.addBoardToList(response[1]);
}
}
render() {
return <MainNavigator />;
}
}
const mapStateToProps = state => ({
boards: state.configurationReducer.boards,
});
const mapDispatchToProps = dispatch => ({
addBoardToList: (board) => {
dispatch(addBoardToList(board));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
configurationReducer.js
const initialState = {
theme: 1,
obscure: false,
boards: [],
boardsList: [],
};
const configurationReducer = (state = initialState, action) => {
let newState = { ...state };
switch (action.type) {
case 'ADD_BOARD':
newState = {
boards: [...state.boards, action.payload],
};
return newState;
case 'REMOVE_BOARD':
newState = {
boards: action.payload,
};
return newState;
case 'ADD_BOARD_TO_LIST':
newState = {
boardsList: [...state.boardsList, action.payload],
};
return newState;
default:
return state;
}
};
export default configurationReducer;
configurationActions.js
function addBoard(board) {
return {
type: 'ADD_BOARD',
payload: board,
};
}
function removeBoard(board) {
return {
type: 'REMOVE_BOARD',
payload: board,
};
}
function addBoardToList(board) {
return {
type: 'ADD_BOARD_TO_LIST',
payload: board,
};
}
export { addBoard, removeBoard, addBoardToList };
I really don't have a clue what is causing this, maybe it's a bug but I don't know if is react-redux fault or react native itself.
When you remove the board, it looks like in you reducer, you return a strange new state:
case 'REMOVE_BOARD':
newState = {
boards: action.payload,
};
return newState;
Should the boards to be an array always? I think you missed something, for example:
boards: state.boards.filter ((it) => it.id !== action.payload.id),