Search code examples
redux-sagareact-boilerplate

Show/hide a component using event handle in redux-saga


I'm trying to build a redux-saga program. The flow is that when I click Test button, the text "Click button to hide" will be disapeared. I dont know what to handle next and how. Please help me. Thanks in advance! Here is my incompleted code:

constants.js

export const TEST_ACTION = 'app/TestPage/TEST_ACTION';

actions.js

export function defaultAction() {
  return {
    type: TEST_ACTION,
  };
}

reducer.js

export const initialState = fromJS({});
function testPageReducer(state = initialState, action) {
  switch (action.type) {
    case TEST_ACTION:
      return state;
    default:
      return state;
  }
}
export default testPageReducer;

messages.js

import { defineMessages } from 'react-intl';
export const scope = 'app.containers.TestPage';
export default defineMessages({
  header: {
    id: `${scope}.header`,
    defaultMessage: 'Click button to hide',
  },
});

Loadable.js

import loadable from 'loadable-components';
import LoadingIndicator from 'components/LoadingIndicator';
export default loadable(() => import('./index'), {
  LoadingComponent: LoadingIndicator,
});

saga.js

import { takeEvery } from 'redux-saga/effects';
import { TEST_ACTION } from './constants';

// Individual exports for testing
export function* testPageSaga() {
}
export default function* rootSaga() {
  yield takeEvery(TEST_ACTION, testPageSaga);
}

index.js

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Helmet } from 'react-helmet';
import { FormattedMessage } from 'react-intl';
import { createStructuredSelector } from 'reselect';
import { compose } from 'redux';
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
import { Button } from 'antd';
import makeSelectTestPage from './selectors';
import reducer from './reducer';
import saga from './saga';
import messages from './messages';

export class TestPage extends React.PureComponent {
  render() {
    return (
      <div>
        <Helmet>
          <title>TestPage</title>
          <meta name="description" content="Description of TestPage" />
        </Helmet>
        <Button onClick={}>Test</Button>
        <FormattedMessage {...messages.header} />
      </div>
    );
  }
}
TestPage.propTypes = {
  dispatch: PropTypes.func.isRequired,
};
const mapStateToProps = createStructuredSelector({
  testPage: makeSelectTestPage(),
});
function mapDispatchToProps(dispatch) {
  return {
    dispatch,
  };
}
const withConnect = connect(
  mapStateToProps,
  mapDispatchToProps,
);
const withReducer = injectReducer({ key: 'testPage', reducer });
const withSaga = injectSaga({ key: 'testPage', saga });
export default compose(
  withReducer,
  withSaga,
  withConnect,
)(TestPage)

Solution

  • You don't need a saga in this particular case you can simply import your constant in your reducer. Here's a full implementation:

              // constants.js
              export const TOGGLE_BUTTON = 'App/TestPage/TOGGLE_BUTTON';
    
              // actions.js
    
              import { TOGGLE_BUTTON } from './constants';
    
              export const toggleButton = () => {
                return {
                  type: 'TOGGLE_BUTTON',
                };
              }
    
              // reducer.js
    
              import { TOGGLE_BUTTON } from './constants';
    
              export const initialState = fromJS({
                showText: true,
              });
    
              function testPageReducer(state = initialState, action) {
                switch (action.type) {
                  case TOGGLE_BUTTON:
                    return state.update('showText', prevValue => !prevValue);
                  default:
                    return state;
                }
              }
              export default testPageReducer;
    
    
              // index.js
    
              import { toggleButton } from './actions';
    
              export class TestPage extends React.PureComponent {
                render() {
                  const { onClick, testPage: { showText } } = this.props;
    
                  return (
                    <div>
                      <Helmet>
                        <title>TestPage</title>
                        <meta name="description" content="Description of TestPage" />
                      </Helmet>
                      <Button onClick={onClick}>Test</Button>
                      { showText && <FormattedMessage {...messages.header} />}
                    </div>
                  );
                }
              }
    
              TestPage.propTypes = {
                dispatch: PropTypes.func.isRequired,
                onClick: PropTypes.func.isRequired,
                testPage: PropTypes.shape({
                  showText: PropTypes.bool,
                }),
              };
    
              const mapStateToProps = createStructuredSelector({
                testPage: makeSelectTestPage(),
              });
    
              function mapDispatchToProps(dispatch) {
                return {
                  onClick: () => dispatch(toggleButton()),
                };
              }
              const withConnect = connect(
                mapStateToProps,
                mapDispatchToProps,
              );
              const withReducer = injectReducer({ key: 'testPage', reducer });
              const withSaga = injectSaga({ key: 'testPage', saga });
              export default compose(
                withReducer,
                withSaga,
                withConnect,
              )(TestPage)