D
D
Dmitry2019-05-02 10:17:50
React
Dmitry, 2019-05-02 10:17:50

Is it possible to avoid duplicate action in React?

Hello, there is an action

actions/videotips.js

export const setSingleVideotip = (slug) => {
    return async dispatch => {
        dispatch({type: SET_VIDEOTIP_SINGLE});
        axios.get(`/api/videotips/${slug}`).then(data => {
            const {videotip} = data.data;
            if (videotip) {
                dispatch({type: SET_VIDEOTIP_SINGLE_SUCCEEDED, payload: videotip});
            } else {
                dispatch({type: SET_VIDEOTIP_SINGLE_FAILED, payload: 404});
            }
        }).catch(err => {
            dispatch({type: SET_VIDEOTIP_SINGLE_FAILED, payload: 404});
        });
    };
};

I use it on the page of one video advice and on the main page to display one advice.
On the page of one tip, the slug is, respectively, the slug of the product
import React, {Component} from 'react';
import Breadcrumbs from '../../../helpers/breadcrumbs';
import Preloader from '../../../helpers/preloader';
import {Route} from 'react-router-dom';
import ErrorPage from '../ErrorPage';
import VideotipPopupWrapper from './VideotipPopupWrapper';


class VideotipSinglePage extends Component {
    constructor(props){
        super(props);
        this.state = {
            videotipSlug: this.props.match.params.videotip,
        };
    }

    componentDidMount() {
        const {setSingleVideotip} = this.props;
        const {videotipSlug} = this.state;
        setSingleVideotip(videotipSlug);
    }

    render(){
        const {videotipSingle: {title, video, image}, isVideotipSingleLoading, isVideotipSingleReady, videotipSingleError} = this.props;

        if (videotipSingleError === 404) {
            return <Route component={ErrorPage} />
        }

        if (isVideotipSingleLoading) {
            return <Preloader />
        }

        if (!isVideotipSingleReady) {
            return null;
        }

        return (
            <React.Fragment>
                <div className="container">
                    <div className="row">
                        <div className="col-xs-12">
                            <Breadcrumbs />
                        </div>
                    </div>
                </div>
                <div className="movietiphome_single">
                    <div className="container movietiphome_single__titleContainer">
                        <div className="row movietiphome_single__titleRow">
                            <div className="col-xs-12 movietiphome_single__titleCol">
                                <div className="movietiphome_single__title home__sectionTitle">
                                    {title}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div className="container movietiphome_single__container">
                    <div className="row movietiphome_single__row">
                        <div className="col-xs-12 movietiphome_single__col">
                            <VideotipPopupWrapper data={{title, video, image}} />
                        </div>
                    </div>
                </div>
            </React.Fragment>
        );
    }
}

export default VideotipSinglePage;

on the main page instead of slug I pass a string 'showonhomepage'
to get a request
Route::get('videotips/showonhomepage', 'Api\[email protected]');

for controller
public function show($id)
    {
        $videotip = DB::table('videotips')->where('slug', $id)->first();
        return response()->json([
            'videotip' => $videotip,
        ]);
    }

    public function showOnHomePage()
    {
        $videotip = DB::table('videotips')->where('show_on_homepage', true)->first();
        return response()->json([
            'videotip' => $videotip,
        ]);
    }

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {setSingleVideotip} from '../actions/videotips';
import VideotipPopupWrapper from '../components/pages/VideotipsPage/VideotipPopupWrapper';
import Preloader from "../helpers/preloader";

class Movietiphome extends Component {
    componentDidMount() {
        const {setSingleVideotip} = this.props;
        const videotipSlug = 'showonhomepage';
        setSingleVideotip(videotipSlug);
    }

    render(){
        const {
            videotipSingle: {title, video, image},
            isVideotipSingleLoading, isVideotipSingleReady, videotipSingleError
        } = this.props;

        if (videotipSingleError) {
            return null;
        }

        return (
            <div className="movietiphome" style={{background: 'url(/uploads/2018/08/movietiphome_bg.png) no-repeat center top',WebkitBackgroundSize: '100% 100%',backgroundSize: '100% 100%'}}>
                <div className="container movietiphome__titleContainer">
                    <div className="row movietiphome__titleRow">
                        <div className="col-xs-12 movietiphome__titleCol">
                            <div className="movietiphome__title home__sectionTitle">
                                Видеосоветы
                            </div>
                        </div>
                    </div>
                </div>

                <div className="container movietiphome__container">
                    <div className="row movietiphome__row">
                        <div className="col-xs-12 movietiphome__col">
                            {isVideotipSingleLoading && <Preloader />}
                            {isVideotipSingleReady && <VideotipPopupWrapper data={{title, video, image}} />}
                        </div>

                    </div>
                </div>
            </div>
        );
    }
}

const mapStateToProps = ({videotips: {videotipSingle, isVideotipSingleLoading, isVideotipSingleReady, videotipSingleError}}) => ({
    videotipSingle,
    isVideotipSingleLoading,
    isVideotipSingleReady,
    videotipSingleError
});

const mapDispatchToProps = dispatch => ({
    setSingleVideotip: videotip => dispatch(setSingleVideotip(videotip)),
});

export default connect(mapStateToProps, mapDispatchToProps)(Movietiphome);

The problem is that if an error occurred on the main page and worked
dispatch({type: SET_VIDEOTIP_SINGLE_FAILED, payload: 404});

, then there will also be an error on the page of one tip.
How is it right? Create another action? Or somehow remove SET_VIDEOTIP_SINGLE_FAILED from the store using componentWillUnmount, for example? (I encounter this for the first time)
Thank you

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Anton Spirin, 2019-05-02
@ddimonn8080

Well, the case itself is quite rare. You have this hint and the error is unlikely. If, after going to the help page, update the key in componentDidMount upon request, then in case of an error on the main page, users should not notice anything.
However, you can store errors by key:

const initialState = {
  tip: null,
  isFetching: false,
  errors: {},
};

case FETCH_VIDEO_TIP_FAILED:
  return {
    ...state,
    isFetching: false,
    errors {
      [payload.slug]: payload.error,
    },
  };

mapStateToProps for a single page:
const mapStateToProps = (state, ownProps) => ({
  error: state.videotips.errors[ownProps.match.params.slug],
});

mapStateToProps for main:
const mapStateToProps = (state) => ({
  error: state.videotips.errors.homepage,
});

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question