Can't access array element in render mode even if it exists - android

I have React native project with redux state manager, using redux-saga and immer for dealing with immutables. There is a simple screen, where i fetch news, using onFocusEffect(). I get data correctly (debug with flipper and redux debugger plugin), but when i try to access news.news.headerImages[0] my app crashes with ERROR TypeError: Cannot convert undefined value to object.
So, here is the code:
Action creator:
const startLoadNews = (id) => {
return { type: Types.START_LOAD_NEWS, id };
};
Saga:
function* fetchNews(action) {
try {
const news = yield call(FakeApi.getNewsLocal, action.id);
yield put(newsActions.loadNewsSuccess(news));
} catch (error) {
yield put(newsActions.loadNewsError('Cant load news'));
}
}
function* watchNews() {
yield takeLatest(types.START_LOAD_NEWS, fetchNews);
}
export function* newsSaga() {
yield all([watchNews()]);
}
Reducer:
const initialState = {
news: {},
loading: false,
error: '',
};
export const newsReducer = (state = initialState, action) =>
produce(state, draft => {
switch (action.type) {
case types.START_LOAD_NEWS:
draft.loading = true;
draft.error = '';
draft.news = {};
break;
case types.LOAD_NEWS_SUCCESS:
draft.loading = false;
draft.error = '';
draft.news = {...action.news};
break;
case types.LOAD_NEWS_ERROR:
draft.loading = false;
draft.error = action.error;
draft.news = {};
break;
}
});
And my NewsScreen component, connected to store:
export const NewsScreen = (params) => {
const { route, news, loadNews } = params;
const { newsId } = route.params;
useFocusEffect(
useCallback(() => { loadNews(newsId); }, [])
);
const testImg = 'https://img.freepik.com/free-photo/confident-business-team-with-leader_1098-3228.jpg';
return (
news.loading ? (
<Spinner/>
) : (
<View style={styles.container}>
<ScrollView>
{true && (
<TouchableOpacity>
<ImageBackground style={styles.image} source={{uri: news.news.headerImages[0]}}>
<View style={styles.notifyer}>
<Notifyer>1-3</Notifyer>
</View>
</ImageBackground>
</TouchableOpacity>
)}
<View style={styles.content}>
<View style={styles.header}>
<Text style={styles.dimmed}>{jsDateTodmY(news.news.date)} | <Text>{news.news.category} </Text></Text>
</View>
<View style={styles.textArea}>
<Text style={styles.newsText}>{news.news.fullText}</Text>
</View>
<View style={styles.footer}>
<Text style={styles.sourceTitle}>Source</Text>
<Text style={styles.source}>{news.news.source}</Text>
</View>
</View>
</ScrollView>
</View>
)
);
};
So, if i replace news.news.headerImages[0] with testImg it loads good, event if i access to news object below in code. Where i do wrong?

Figured it out:
After first render there is no news.news.headerImages array of my state, so when i try to acccess to undefined.[index] it crashes. Fixed it by adding an array to my initial state:
const initialState = {
news: { headerImages:[] },
loading: false,
error: '',
};

Related

java.lang.IllegalArgumentException: No view found for id 0x6d95 (unknown) for fragment VideoFragment{eba3edd #1 id=0x6d95} and app is crashing

In below code the I am having problem in setContainerWidth(width);from onLayout method, as the app is directly crashing on android device. I have created one button in another component and it is opening this component as dialoguebox.
const YoutubeVideoPlayer = props => {
const {visibility, onChangeVisibility, data} = props;
const youtubePlayerRef = useRef();
const singleVideoId = data;
const isPlaying = true;
const isLooping = true;
const [containerMounted, setContainerMounted] = useState(false);
const [containerWidth, setContainerWidth] = useState(null);
return (
<ModalViewYoutube
visibility={visibility}
onChangeVisibility={onChangeVisibility}>
<View>
<ScrollView
style={styles.container}
onLayout={({
nativeEvent: {
layout: {width},
},
}) => {
if (!containerMounted) {
setContainerMounted(true);
}
if (containerWidth !== width) {
setContainerWidth(width);
}
}}>
{containerMounted && (
<YouTube
ref={youtubePlayerRef}
apiKey={AppConstants.GOOGLE_LOCATION_KEY}
videoId={singleVideoId}
play={isPlaying}
loop={isLooping}
controls={1}
style={[styles.player]}
/>
)}
</ScrollView>
</View>
</ModalViewYoutube>
);
};
export default YoutubeVideoPlayer;

About react native vision camera taking picture and save

I am new in react native. What do I need to do if I want to have a picture on the desktop after I click on the button? Just simply want to take a picture. I have tried to do so and succeed yesterday but I can't do that now.
function Cam() {
const [hasPermission, setHasPermission] = React.useState(false);
const isFocused = useIsFocused()
const devices = useCameraDevices()
const device = devices.back
const camera = useRef(null)
const takePhotoOptions = {
qualityPrioritization: 'speed',
flash: 'off'
};
React.useEffect(() => {
(async () => {
const status = await Camera.requestCameraPermission();
setHasPermission(status === 'authorized');
})();
}, []);
const takePhoto = async () => {
try {
//Error Handle better
if (camera.current == null) throw new Error('Camera Ref is Null');
console.log('Photo taking ....');
const photo = await camera.current.takePhoto(takePhotoOptions);
console.log(photo.path)
} catch (error) {
console.log(error);
}
};
function renderCamera() {
if (device == null) {
return (
<View>
<Text style={{ color: '#fff' }}>Loading</Text>
</View>
)
}
else {
return (
<View style={{ flex: 1 }}>
{device != null &&
hasPermission && (
<>
<Camera
ref={camera}
style={StyleSheet.absoluteFill}
device={device}
isActive={isFocused}
photo={true}
/>
<Text> Too much code, I delete something here </Text>
</>
)}
</View>
)
}
}
return (
<View style={{ flex: 1 }}>
{renderCamera()}
</View>
);
}
export default Cam;
enter image description here
as you can see here, the frame is not important for now.
You can use react-native-fs
// Create pictureDirectory if it does not exist
await RNFS.mkdir(pictureDirectory);
// Move picture to pictureDirectory
const filename = R.last(data.path.split('/'))!;
await RNFS.moveFile(data.path, `${pictureDirectory}/${filename}`);
import {Camera} from 'react-native-vision-camera';
instead of using const camera = useRef(null) use const camera = useRef<Camera>(null)

Real-time line charting with React-Native

I'm new to drawing a graph with react-native. The problem is, I can read the data sent with Ble as a value on the screen, but I'm having trouble making real-time graphs. There must be a mistake somewhere. I tried many different methods.
The code below is my screen code.
const disconnectDevice = useCallback(async () => {
navigation.goBack();
const isDeviceConnected = await device.isConnected();
if (isDeviceConnected) {
await device.cancelConnection();
navigation.navigate('Home');
}
}, [device, navigation]);
useEffect(() => {
const getDeviceInformations = async () => {
// connect to the device
const connectedDevice = await device.connect();
setIsConnected(true);
// discover all device services and characteristics
const allServicesAndCharacteristics = await connectedDevice.discoverAllServicesAndCharacteristics();
// get the services only
const discoveredServices = await allServicesAndCharacteristics.services();
setServices(discoveredServices);
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Permission Localisation Bluetooth',
message: 'Requirement for Bluetooth',
buttonNeutral: 'Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
};
getDeviceInformations();
device.onDisconnected(() => {
navigation.navigate('Home');
});
// give a callback to the useEffect to disconnect the device when we will leave the device screen
return () => {
disconnectDevice();
navigation.navigate('Home');
};
}, [device, disconnectDevice, navigation]);
return (
<ScrollView contentContainerStyle={styles.container}>
<TouchableOpacity style={styles.button} onPress={disconnectDevice}>
<Text style={{fontFamily:"SairaExtraCondensed-Thin",textAlign:"center",fontSize:15,color:"white"}}>Antrenmanı Sonlandır</Text>
</TouchableOpacity>
<View>
<View style={styles.header} >
<Text>{`Name : ${device.name}`}</Text>
<Text>{`Is connected : ${isConnected}`}</Text>
</View>
<View>
<>
{services &&
services.map((service) => {
return(
<>
<ServiceCard service={service} />
<LineChart
style={{ height: 200 }}
gridMin={0}
gridMax={300}
data={[service]}
svg={{ stroke: 'rgb(134, 65, 244)' }}
contentInset={{ top: 20, bottom: 20 }}>
</LineChart></>
)
})}
</>
</View>
</View>
<View>
</View>
</ScrollView>
);
};
The service component, where the values ​​were decoded last, is as follows;
type ServiceCardProps = {
service: Service;
};
const ServiceCard = ({ service }: ServiceCardProps) => {
const [descriptors, setDescriptors] = useState<Descriptor[]>([]);
const [characteristics, setCharacteristics] = useState<Characteristic[]>([]);
const [areCharacteristicsVisible, setAreCharacteristicsVisible] = useState(
false,
);
useEffect(() => {
const getCharacteristics = async () => {
const newCharacteristics = await service.characteristics();
setCharacteristics(newCharacteristics);
newCharacteristics.forEach(async (characteristic) => {
const newDescriptors = await characteristic.descriptors();
setDescriptors((prev) => [...new Set([...prev, ...newDescriptors])]);
});
};
getCharacteristics();
}, [service]);
return (
<View style={styles.container}>
<TouchableOpacity
onPress={() => {
setAreCharacteristicsVisible((prev) => !prev);
}}>
<Text>{`UUID : ${service.uuid}`}</Text>
</TouchableOpacity>
{areCharacteristicsVisible &&
characteristics &&
characteristics.map((char) => (
<CharacteristicCard key={char.id} char={char} />
))}
{descriptors &&
descriptors.map((descriptor) => (
<DescriptorCard key={descriptor.id} descriptor={descriptor} />
))}
</View>
);
};
Data is being decoded with Ble. Then it is displayed as a value on the screen via the latest service map. I want to see the graph on the screen in real time like in this code. What error could be below?
Nothing appears on the screen. I only see values.
Thanks

React Native Sqlite Storage: db.transaction() function is not executed

I'm working with React-native-sqlite-storage (React native CLI). And the thing is that getmysqliData dosn't excute tx.executeSql function when I query the sqlite. And I don't know why.
the whole code is this:
https://gist.github.com/BravenxX/247f97c0576881616c24d197cdd137f6
About the code:
state: data: [--DATA--] .... is temporaly, this should must be replaced with the sqlite elements in getMysqliData function.
the are 2 arrays because I use them as a real time filter (it has nothing to do with sqlite btw)
const db = SQLite.openDatabase({ name: "geslub", createFromLocation: "~databases/geslub.db" });
class TablaActProgramadas extends Component{
constructor(props){
super(props);
this.state={
value: '',
isLoading: true,
data:[
{'Faena': 'aDDLB', 'Planta': 'taller Titan', 'Linea': 'Kmotasú', 'Equipo': 'Caex', 'Componente': 'N/A'}
],
arrayholder: [
{'Faena': 'aDDLB', 'Planta': 'taller Titan', 'Linea': 'Kmotasú', 'Equipo': 'Caex', 'Componente': 'N/A'}
],
};
};
async componentDidMount(){
await this.getMysqliData();
console.log('TERMINO: ComponenntDIDMOUNT')
}
getMysqliData(){
const sql = 'SELECT * FROM actividades_programadas';
db.transaction((tx) => {
//TX.EXECUTESQL is not executed!!
tx.executeSql(sql, [], (tx, results) => {
if(results.rows._array.length > 0){
this.setState({
data: results.rows_array,
arrayholder: results.rows_array,
isLoading: false
})
}else{
Alert.alert('ERROR en la carga de datos')
}
});
});
}
componentWillUnmount() {
this.closeDatabase();
}
closeDatabase = () => {
if (db) {
db.close();
} else {
console.log("Database no estaba abierta");
}
}
renderHeader = () => {
return (
<SearchBar
placeholder="Filtro general..."
lightTheme
round
onChangeText={text => this.searchFilterFunction(text)}
autoCorrect={false}
value={this.state.value}
/>
);
};
searchFilterFunction = text => {
this.setState({
value: text,
});
const newData = this.state.arrayholder.filter(item => {
const itemData = `${item.Faena.toUpperCase()} ${item.Planta.toUpperCase()} ${item.Linea.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
data: newData,
});
};
render(){
if(this.state.isLoading)
return (
<View style={stylesLoading.container}>
<View>
<ActivityIndicator size="large" color="lightblue"/>
</View>
<View>
<Text style={stylesLoading.texto}>
Descargando datos...
</Text>
</View>
</View>
)
else
return(
<FlatList
data={this.state.data}
showsVerticalScrollIndicator={false}
keyExtractor={(item, index) => index.toString()}
renderItem={({item}) =>(
<TouchableOpacity onPress={() => this.props.navigation.navigate('RealizarActProgramadas', {
faena: `${item.Faena}`, //ENVIAR ID DE LA ACTIVIDAD A REALIZAR
otherParam: 'anything you want here',
})}>
<ListItem
title={`Faena: ${item.Faena}`}
subtitle={`Planta: ${item.Planta}\nLinea: ${item.Linea}`}
/>
</TouchableOpacity>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader()}
/>
);
}
}
I have the same issue. This ocurred because you openDasaBase is create a new database file and not use your imported file.
In my case for android I needed to put de sqlite file in android/src/main/assets/www/test.db
And use this config to open:
var db = openDatabase({name: 'test.db', createFromLocation: 1}, () => {
console.log("Database OPENED");
}, (err) => {
console.log("SQL Error: " + err);
});
This is better described in docs https://github.com/andpor/react-native-sqlite-storage#importing-a-pre-populated-database

Component does not re-render correctly when store updates

I call myGET_REQUESTaction in a screen, my Sagamakes the request and triggers my GET_SUCCESS action but, my screen doesn't re-render on it's own, only when I update the component's state, a re-render is triggered and the new props reflecting the store show up.
so... my store apparently works fine, in Reactotron the store is filled, as you can see below:
https://user-images.githubusercontent.com/27635248/54751638-52671b80-4bba-11e9-9f9b-b7eee7f3deba.png
My user Reducer:
export const Types = {
GET_SUCCESS: 'user/GET_SUCCESS',
GET_REQUEST: 'user/GET_REQUEST',
GET_FAILURE: 'user/GET_FAILURE',
UPDATE_USER: 'user/UPDATE_USER',
REHYDRATE_SUCCESS: 'user/REHYDRATE_SUCCESS',
REHYDRATE_FAILURE: 'user/REHYDRATE_FAILURE',
}
const INITIAL_STATE = {
data: {},
status: {
loading: false,
error: null,
}
}
export default function user(state = INITIAL_STATE, action) {
switch (action.type) {
case Types.GET_SUCCESS: {
return {
...state,
data: action.payload.user,
status: {
...state.status,
loading: false,
error: null
}
}
}
case Types.GET_REQUEST: {
return {
...state,
status: {
error: null,
loading: true
}
}
}
case Types.GET_FAILURE: {
if (Object.keys(state.data).length) {
action.payload.isStateEmpty = false
return {
...state,
status: {
...state.status,
loading: false
}
}
} else {
return {
...state,
status: {
...state.status,
loading: false
}
}
}
}
case Types.REHYDRATE_SUCCESS: {
return {
...state,
data: action.payload.user,
status: {
error: null,
loading: false
}
}
}
case Types.REHYDRATE_FAILURE: {
return {
...state,
status: {
loading: false,
error: action.payload.error
}
}
}
case Types.UPDATE_USER: {
return {
...state,
data: {
...state.data,
...action.payload.data
}
}
}
default: {
return state
}
}
}
export const Creators = {
getUserSuccess: user => ({
type: Types.GET_SUCCESS,
payload: {
user,
},
}),
getUserRequest: () => ({
type: Types.GET_REQUEST,
payload: {}
}),
getUserFailure: error => ({
type: Types.GET_FAILURE,
payload: {
error,
isStateEmpty: true
}
}),
rehydrateUserSuccess: user => ({
type: Types.REHYDRATE_SUCCESS,
payload: {
user
}
}),
rehydrateUserFailure: error => ({
type: Types.REHYDRATE_FAILURE,
payload: {
error
}
}),
updateUser: data => ({
type: Types.UPDATE_USER,
payload: {
data
}
}),
}
My user saga:
import { Types } from '../ducks/user'
import { call, put, takeLatest } from 'redux-saga/effects'
import { Creators as UserActions } from '../ducks/user'
import API from 'utils/api'
import DAO from '../../utils/dao';
function formatUsuarioToDbKeys(usuario, pk_pessoa) {
return {
pk_user: usuario.id,
fk_pessoa: pk_pessoa,
username_usu: usuario.username,
email_usu: usuario.email,
first_name_usu: usuario.first_name,
las_name_usu: usuario.last_name,
ativo_usu: usuario.ativo,
}
}
function formatPessoaToDbKeys(pessoa) {
return {
pk_pessoa: pessoa.pessoa_id,
fk_funcao: pessoa.funcao_id,
nome_pes: pessoa.nome,
codigo_erp_pes: pessoa.codigo_erp,
ativo_pes: pessoa.ativa,
}
}
function formatFuncaoToDbKeys(funcao) {
return {
pk_funcao: funcao.id,
nome_fun: funcao.nome,
}
}
function formatEquipeToDbKeys(equipe) {
return {
pk_equipe: equipe.id,
nome_equ: equipe.nome,
ativo_equ: equipe.ativo,
}
}
function* getUser() {
try {
const dados = yield call(API.getInstance().getRequest, '/initializer/?tipo=1')
const funcao = yield call(formatFuncaoToDbKeys, dados.funcao)
const pessoa = yield call(formatPessoaToDbKeys, dados.pessoa)
const usuario = yield call(formatUsuarioToDbKeys, ...[dados.usuario, dados.pessoa.pessoa_id])
const equipe = yield call(formatEquipeToDbKeys, dados.equipe)
yield put(UserActions.getUserSuccess({ usuario, pessoa, funcao, equipe }))
yield call(DAO.getInstance().createFuncao, funcao)
yield call(DAO.getInstance().createPessoa, pessoa)
yield call(DAO.getInstance().createUsuario, usuario)
yield call(DAO.getInstance().createEquipe, equipe)
} catch (error) {
yield put(UserActions.getUserFailure('Ocorreu um erro ao buscar dados do usuário.'))
yield call(console.warn, error.message)
}
}
function* rehydrateUser(action) {
if (action) {
try {
const user = yield call(DAO.getInstance().getUsuario)
yield put(UserActions.rehydrateUserSuccess(user))
} catch (error) {
yield put(UserActions.rehydrateUserFailure('Ocorreu um erro ao buscar dados do usuário.'))
yield call(console.warn, error.message)
}
}
}
export default sagas = [
takeLatest(Types.GET_REQUEST, getUser),
takeLatest(Types.GET_FAILURE, rehydrateUser)
]
and, finally this is my component:
class Dashboard extends Component {
...state and others methods
componentDidMount() {
this.props.getUserRequest()
this.props.getConstructionsRequest()
}
render() {
const spin = this.state.spin_value.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
return (
<View style={{ flex: 1 }}>
<StatusBar
hidden={false}
backgroundColor={colors.blueDarker} />
<ScrollView
ref={'refScrollView'}
stickyHeaderIndices={[2]}
style={styles.container}>
<ImageBackground
source={require('imgs/capa_dashboard.png')}
blurRadius={4}
style={styles.imageBackground}>
<View style={styles.headerContainer}>
<Text style={styles.textVersion}>{require('../../../package.json').version}</Text>
<Animated.View style={{ transform: [{ rotate: spin }] }}>
<TouchableOpacity
onPress={() => {
this._spinIcon()
this._handleRefresh()
}}>
<MaterialIcons
name={'refresh'}
size={35}
style={styles.refreshIcon}
color={'white'} />
</TouchableOpacity>
</Animated.View>
</View>
<View style={styles.headerButtonsContainer}>
<HeaderLeft
navigation={this.props.navigation} />
<Image
style={styles.image}
source={require('imgs/logo_header.png')} />
<HeaderRight />
</View>
<View style={{ flex: 1, justifyContent: 'center' }}>
{!this.props.user.status.loading && !!Object.keys(this.props.user.data).length
? <View>
<Text style={[styles.textNome, { textAlign: 'center' }]}>{this.props.user.data.pessoa.nome_pes}</Text>
<Text style={styles.textAuxiliar}>{this.props.user.data.funcao.pk_funcao == 1 ? this.props.user.data.equipe.nome_equ : 'Engenheiro(a)'}</Text>
</View>
: <ActivityIndicator style={{ alignSelf: 'center' }} size={'large'} color={colors.blue} />
}
</View>
</ImageBackground>
<ActionsButtons
stylesButton1={{ borderBottomColor: this.state.button_obras_selected ? 'white' : colors.transparent }}
stylesText1={{ color: this.state.button_obras_selected ? 'white' : 'lightgrey' }}
numberButton1={this.props.count_obras}
callbackButton1={async () => this.setState({ button_obras_selected: true })}
stylesButton2={{ borderBottomColor: !this.state.button_obras_selected ? 'white' : colors.transparent }}
stylesText2={{ color: !this.state.button_obras_selected ? 'white' : 'lightgrey' }}
numberButton2={this.state.count_enviar}
callbackButton2={async () => this.setState({ button_obras_selected: false })}
/>
<View>
{this.state.button_obras_selected
? <View style={styles.containerTextInput} >
<TextInput
onEndEditing={() => this._handleEndSearch()}
onFocus={() => this._handleStartSearch()}
ref={'textInputRef'}
style={styles.textInput}
onChangeText={search_text => this._filterSearch(search_text)}
autoCapitalize="none"
onSubmitEditing={() => this._handleClickSearch()}
underlineColorAndroid='rgba(255,255,255,0.0)'
placeholder={'Buscar obras...'} />
<TouchableOpacity
onPress={() => this._handleClickSearch()}
style={styles.searchImage}>
<MaterialCommunityIcons
name={'magnify'}
size={30}
color={'black'} />
</TouchableOpacity>
</View >
: null}
</View>
<View>
{this.state.button_obras_selected
? !this.props.constructions.status.loading && !!Object.keys(this.props.constructions.data).length
? <View style={{ flex: 1, marginTop: 8 }}>
<FlatList
data={this.props.constructions.data}
removeClippedSubviews={true}
keyExtractor={item => item.pk_obra.toString()}
renderItem={obra =>
<ObraComponent
callback={this._callbackObra}
item={obra.item}
isCurrentObra={nome => this.state.obra_atual == nome}
/>
}
/>
</View>
: <ActivityIndicator style={{ marginTop: 150 }} size={50} color={colors.blueDarker} />
:
<View style={{
flex: 1,
marginTop: 8,
}}>
<FlatList
data={[]}
removeClippedSubviews={true}
keyExtractor={item => item.fk_obra.toString()}
renderItem={acao =>
<AcaoComponent item={acao.item} />
}
/>
</View>
}
</View>
</ScrollView>
</View>
)
}
}
const mapStateToProps = state => ({
user: state.user,
constructions: state.constructions,
count_obras: state.constructions.data.length
})
const mapDispatchToProps = dispatch =>
bindActionCreators({
...UserActions,
...ConstructionsActions.DEEP,
...ConstructionsActions.SHALLOW
}, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard)
As I said before, I call getUserRequest() to fire GET_REQUEST action on componentDidMount() but, when the request is done and my redux store is updated, my screen stays loading like this, even if the loading state in the store is false
https://user-images.githubusercontent.com/27635248/54752551-4e88c880-4bbd-11e9-9164-5fad46db6c13.png
I've used very similar store and saga structures in other projects, but for some reason, in this specific one, I haven't been able to figure it out
When I press one of these buttons, the component updates it's state and this triggers a re-render, then finally the data from my store shows up as props in the censored areas - this was the only way I figured out to re-render stuff with redux(in this project at least), forcing a re-render by updating the components state using this.setState():
https://user-images.githubusercontent.com/27635248/54752771-fef6cc80-4bbd-11e9-9d15-a46acb87f3a4.png
I'm not sure what's wrong with my implementation, i've checked out other similiar issues, none of them seemed to work, if anyone has a suggestion, feel welcome to post them below, thank you in advance.
"axios": "^0.18.0",
"react-native": "~0.55.2",
"react-redux": "^6.0.0",
"reactotron-redux": "^2.1.3",
"reactotron-redux-saga": "^4.0.1",
"redux": "^4.0.1",
"redux-saga": "^1.0.1",
EDIT:
So, as far as my understanding goes, updating redux's store reflectes on new props to the connected components, and React does update them based on a shallow compare. I've experimented a bit, and for some reason, my actions are triggered, sagas run fine, and the store is changing successfuly, but mapStateToProps is not being called after my success action is triggered.
Basically I'm not able to choose if the component should update (using shouldComponentUpdate to compare prevProps and this.props) because the component is not even receiving new props from mapStateToProps.

Categories

Resources