Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reducer not updating state #13

Closed
bernardbaker opened this issue Nov 16, 2018 · 5 comments
Closed

Reducer not updating state #13

bernardbaker opened this issue Nov 16, 2018 · 5 comments

Comments

@bernardbaker
Copy link

bernardbaker commented Nov 16, 2018

I have taken a copy of the boilerplate and I'm having trouble getting the reducer to update the state.

App/Sagas/index.js

// import { ExampleTypes } from 'App/Stores/Example/Actions'
import { StartupTypes } from 'App/Stores/Startup/Actions'
import { WelcomeTypes } from 'App/Stores/Welcome/Actions'
// import { fetchTemperature } from './ExampleSaga'
import { login } from './WelcomeSaga'
import { startup } from './StartupSaga'

export default function* root() {
  yield [
    /**
     * @see https://redux-saga.js.org/docs/basics/UsingSagaHelpers.html
     */
    // Run the startup saga when the application starts
    takeLatest(StartupTypes.STARTUP, startup),
    // Call `fetchTemperature()` when a `FETCH_TEMPERATURE` action is triggered
    // takeLatest(ExampleTypes.FETCH_TEMPERATURE, fetchTemperature),
    // Call `login()` when a `LOGIN` action is triggered
    takeLatest(WelcomeTypes.LOGIN, login),
  ]
}

App/Sagas/WelcomeSaga.js

import WelcomeActions from 'App/Stores/Welcome/Actions'

/**
 * A saga can contain multiple functions.
 *
 * This example saga contains only one to fetch the weather temperature.
 * Feel free to remove it.
 */
export function* login() {
  // Dispatch a redux action using `put()`
  // @see https://redux-saga.js.org/docs/basics/DispatchingActions.html
  yield put(WelcomeActions.loginLoading())

  // Fetch the account from an API
  const account = {foo:'bar'}

  if (account) {
    yield put(WelcomeActions.loginSuccess(account))
  } else {
    yield put(
      WelcomeActions.loginFailure('There was an error while logging in to the app.')
    )
  }
}

App/Stores/Welcome/Actions.js


/**
 * We use reduxsauce's `createActions()` helper to easily create redux actions.
 *
 * Keys are action names and values are the list of parameters for the given action.
 *
 * Action names are turned to SNAKE_CASE into the `Types` variable. This can be used
 * to listen to actions:
 *
 * - to trigger reducers to update the state, for example in App/Stores/Example/Reducers.js
 * - to trigger sagas, for example in App/Sagas/index.js
 *
 * Actions can be dispatched:
 *
 * - in React components using `dispatch(...)`, for example in App/App.js
 * - in sagas using `yield put(...)`, for example in App/Sagas/WelcomeSaga.js
 *
 * @see https://github.com/infinitered/reduxsauce#createactions
 */
const { Types, Creators } = createActions({
  // Login to the game
  login: null,
  // The login operation has started and is loading
  loginLoading: null,
  // The login was successfully
  loginSuccess: ['account'],
  // A login error occurred
  loginFailure: ['loginErrorMessage'],
  // Register to create an account
  register: null,
  // The register operation has started and is loading the result
  registerLoading: null,
  // The registration was successfully
  registerSuccess: ['account'],
  // A registration error occurred
  registerFailure: ['registerErrorMessage'],
  // Play with a guest account
  playAsGuest: null,
  // The register operation has started and is loading the result
  playAsGuestLoading: null,
  // The registration was successfully
  playAsGuestSuccess: ['guestAccount'],
  // A registration error occurred
  playAsGuestFailure: ['registerErrorMessage'],
})

export const WelcomeTypes = Types
export default Creators

App/Containers/WelcomeScreen/WelcomeScreen.js

import { Text, View, Button } from 'react-native'
import { connect } from 'react-redux'
import { PropTypes } from 'prop-types'
import WelcomeActions from 'App/Stores/Welcome/Actions'
import Style from './WelcomeScreenStyle'

/**
 * This is the welcome screen container component
 * 
 * This screen displays a static image which will be replaced with an animation
 * and two buttons, one to login to the game, one to register,
 * and one to play the game as a guest 
 */
export class WelcomeScreen extends React.Component {
    
    render() {
        console.log('this.props.loginIsLoading',this.props.loginIsLoading)
        console.log('this.props.account.foo',this.props.account.foo)
        let foo = this.props.loginIsLoading ? '...' : this.props.account.foo
        console.log('foo',foo)
        if (foo === undefined) {
            foo = '??'
          }
        // Render a welcome message and three buttons
        return (
            // Update with styles object
            <View>
                <Text id="game-name">Log It</Text>
                <Text id="welcome-text">The fun game to play with anyone.</Text>
                <Button id="login" onPress={this.props.login} title="Login"/>
                <Button id="register" onPress={this.props.register} title="Register"/>
                <Button id="play-as-guest" onPress={this.props.playAsGuest} title="Play as guest"/>
                <Text>The account foo value is: {foo}</Text>
            </View>
        )
    }
}

WelcomeScreen.propsTypes = {
    account: {foo: 'baz'},
    loginIsLoading: PropTypes.boolean
}

const mapStateToProps = (state) => ({
    account: state.welcome.get('account'),
    loginIsLoading: state.welcome.get('loginIsLoading')
  })

const mapDispatchToProps = (dispatch) => ({
    login: () => dispatch(WelcomeActions.login()),
    register: () => dispatch(WelcomeActions.register()),
    playAsGuest: () => dispatch(WelcomeActions.playAsGuest()),
  })

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(WelcomeScreen)```
@bernardbaker
Copy link
Author

I've fixed it now, but how can I pass back an object to the reducer.

@JeremyDolle
Copy link
Collaborator

JeremyDolle commented Nov 20, 2018

Hello @bernardbaker , in order to pass an object to a reducer, you'll need to create an associated action ( ⚠️ with the same name ⚠️). You have an example in the boilerplate :

App/Stores/Example/Action.js

const { Types, Creators } = createActions({
  ....
  // The temperature was successfully fetched
  fetchTemperatureSuccess: ['temperature'],
  ....
})

The associated Reducer :
App/Stores/Example/Reducer.js

export const fetchTemperatureSuccess = (state, { temperature }) =>
  state.merge({
    temperature: temperature,
    temperatureIsLoading: false,
    temperatureErrorMessage: null,
  })

Here the object temperature is send to the reducer and the reducer update the state

The action is called in the saga, when you receive the required result.

I hope i understand your issue ! If you have any trouble don't hesitate to ask.

@bernardbaker
Copy link
Author

bernardbaker commented Nov 20, 2018 via email

@JeremyDolle
Copy link
Collaborator

JeremyDolle commented Nov 21, 2018

In the boilerplate you have an exemple :

App/Stores/Example/InitialState.js

....
export const INITIAL_STATE = Map({
  temperature: null,
  ....
})

So, in dev mode, each time you reload your app the state temperature will be set to null.

@JeremyDolle
Copy link
Collaborator

I will close this issue now. I hope i helped you, if you have any troubles you can re-open this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants