4

It's been 5 hours that I'm on the problem but decidedly it does not want to work...

I would like to dispatch the event when onScroll is detected on my home component and receive the status "true" or "false" in my TopNavigation component

For now my reducer works well (with a console.log(nextState) before the render) but I have the impression that the connection does not work with connect(mapStatetoProps)(TopNavigation) because my component does not re-render

Thank you for your answers

//TopNavigation

import React from 'react'
import { connect } from 'react-redux'


class TopNavigation extends React.Component {
    constructor(props) {
        super(props)
    }


    componentDidMount() {
        console.log(this.props.scrollData)
    }
}

// Render things...

const mapStatetoProps = (state) => {
    return {
        scrollData: state.scrollData
    }
}

export default connect(mapStatetoProps)(TopNavigation)

// Home

import React from 'react'
import { StyleSheet, View, FlatList } from 'react-native'
import gStyles from '../../../Styles/global'
import { connect } from 'react-redux'

// Partials
import ItemBox from '../../Partials/ItemBox'
import TopNavigation from '../../Partials/TopNavigation'

// Data
import recetteData from '../../../api/recetteData'


class Home extends React.Component {
    constructor(props) {
        super(props)
    }

    render() {
        return (
            <View style={styles.mainContainer}>
                <FlatList
                    data={recetteData}
                    keyExtractor={(item) => item.id.toString()}
                    onPress={() => this._toggleSet()}
                    renderItem={({ item }) => <ItemBox item={item} />}
                    onScroll={(event) => this.props.dispatch({ type: "POSITION", value: event.nativeEvent.contentOffset.y })}
                    style={styles.flatListContainer} />
                <TopNavigation />
            </View>
        )
    }
}

export default connect(mapStateToProps)(Home)


//ScrollData Reducer

const initialState = {
    scrollData: {
        scrolled: false
    }
}

function scrollData(state = initialState, action) {
    let nextState
    switch (action.type) {
        case 'POSITION':
            if (action.value > 0) {
                nextState = {
                    ...state,
                    scrollData: {
                        ...state.scrollData,
                        scrolled: true,
                    },
                }
            }
            else {
                nextState = {
                    ...state,
                    scrollData: {
                        ...state.scrollData,
                        scrolled: false
                    },
                }
            }
            return nextState.scrollData.scrolled
        default:
            return state
    }
}

export default scrollData

//ConfigureStore

import { createStore } from 'redux';
import buttonPreference from './Reducers/buttonPreference'
import scrollData from './Reducers/scrollData'


export default createStore(/*buttonPreference,*/scrollData)

On console (console.log of componentDidMount of TopNavigation):

Object { "scrolled": false, }

But no change when i'm scrolling

Here is my package.json

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "eject": "expo eject"
  },
  "dependencies": {
    "expo": "^32.0.6",
    "react": "^16.8.3",
    "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.1.tar.gz",
    "react-native-elevated-view": "0.0.6",
    "react-native-gesture-handler": "^1.1.0",
    "react-native-paper": "^2.12.0",
    "react-native-responsive-dimensions": "^2.0.1",
    "react-navigation": "^2.0.1",
    "react-navigation-material-bottom-tabs": "^0.4.0",
    "react-redux": "^6.0.1",
    "redux": "^4.0.1"
  },
  "devDependencies": {
    "babel-preset-expo": "^5.0.0",
    "react-test-renderer": "^16.6.0-alpha.8af6728",
    "schedule": "^0.4.0"
  },
  "private": true
}

Update

Putting on TopNavigation:

//TopNavigation

    constructor(props) {
        super(props)
        this.state = {
            scrolledState: false
        }
    }

    componentDidUpdate(prevProps) { // Instead of componentDidMount
        if (this.props.scrollData.scrolled !== prevProps.scrollData.scrolled) {
            console.log(this.props.scrollData);
            this.setState({ scrolledState: this.props.scrollData });
        }
    }

But it still doesn't work, no event or state change...

Update 2

The store seems to be work oroperly, the problem more precisely is that it does not update in real time the component.

If I populate the store, I quite and return to the page using navigation, the data is well changed.

The real question is, why the component does not update in real time with the new store data passed by the reducer...

Update 3

Expo in production mode solved problem...

3 Answers3

1

You have done everything right for the most part. The problem is with your TopNavigation file. Two important things to keep in mind here:

  1. componentDidMount() is called only once, when your component is rendered for the first time. So even if your connect works correctly, you will not get more than one call to this function. To check if your props are updated correctly, you can have a console.log() inside componentDidUpdate() as follows:

     componentDidUpdate(prevProps) {
         if (this.props.scrollData.scrolled !== prevProps.scrollData.scrolled) {
             console.log(this.props.scrollData);
         }
     }
    
  2. Also keep in mind that this will not cause a re-render of your component. A component re-renders only when the state of the component changes. You can use this change in your props to trigger a state change, which will call the render function again, to trigger a re-render of your component, as follows:

    state = {scrolledState: false};
    
    ...
    ...
    
    componentDidUpdate(prevProps) {
        if (this.props.scrollData.scrolled !== prevProps.scrollData.scrolled) {
            // console.log(this.props.scrollData);
            this.setState({scrolledState: this.props.scrollData});
        }
    }
    

Hope this helps!

Swanky Coder
  • 862
  • 1
  • 8
  • 23
1

That sounds like a bug with environnement. I launched Expo in production mode and it solved problem.

On folder .expo

//setting.json

{
  "hostType": "lan",
  "lanType": "ip",
  "dev": false, // false for production env
  "minify": false,
  "urlRandomness": "53-g5j"
}

I hope it can help but it would be desirable to be able to continue working on dev mode...

I report a bug on expo github

0

The previous answer was right. But to make the code works try the below approach.

class Home extends React.Component {
constructor(props) {
    super(props);
    this.state = {
      scrolling: false;
    }
}

makeScroll = (event) => {
  this.props.dispatch({ type: "POSITION", value: event.nativeEvent.contentOffset.y 
  });
  setTimeout(() => this.setState({scrolling: true}), 150);
}

render() {
    return (
        <View style={styles.mainContainer}>
            <FlatList
                data={recetteData}
                keyExtractor={(item) => item.id.toString()}
                onPress={() => this._toggleSet()}
                renderItem={({ item }) => <ItemBox item={item} />}
                onScroll={(event) => this.makeScroll(event)}
                style={styles.flatListContainer} />
            <TopNavigation />
        </View>
    )
 }
}

export default connect(mapStateToProps)(Home)

Instead of directly dispatch at onScroll event. Pass it into a function and do change the local state inside that after dispatch.

Prabu samvel
  • 1,213
  • 8
  • 19
  • Thank you for your reply, but it still doesn't work. I don't need the state for my Home component and my store is receiving dispatch in both cases. – Nicolas Taraborrelli Mar 24 '19 at 12:51