ddimonn8080
@ddimonn8080

Можно ли избежать дублирования action в React?

Здравствуйте, есть 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});
        });
    };
};

его я использую на странице одного видео-совета и на главной странице для вывода одного совета.
На странице одного совета slug это соответственно slug товара
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;


на главной странице вместо slug передаю строку 'showonhomepage'
чтобы получить запрос
Route::get('videotips/showonhomepage', 'Api\VideotipsController@showOnHomePage');

для контроллера
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);


Проблема в том что если на главной странице произошла ошибка и отработал
dispatch({type: SET_VIDEOTIP_SINGLE_FAILED, payload: 404});

,то на странице одного совета тоже будет ошибка.
Как правильно?Создать другой action?Либо как-то убрать SET_VIDEOTIP_SINGLE_FAILED из store с помощью componentWillUnmount, например?(первый раз сталкиваюсь с таким)

Спасибо
  • Вопрос задан
  • 97 просмотров
Решения вопроса 1
rockon404
@rockon404 Куратор тега React
Frontend Developer
Ну сам кейс довольно редкий. У вас же есть эта подсказка и ошибка маловероятна. Если по переходу на страницу подсказки, обновлять ключ в componentDidMount при запросе, то в случае ошибки на главной, пользователи по идее не должны ничего заметить.

Тем не менее, вы можете хранить ошибки по ключу:
const initialState = {
  tip: null,
  isFetching: false,
  errors: {},
};

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


mapStateToProps для отдельной страницы:
const mapStateToProps = (state, ownProps) => ({
  error: state.videotips.errors[ownProps.match.params.slug],
});


mapStateToProps для главной:
const mapStateToProps = (state) => ({
  error: state.videotips.errors.homepage,
});
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы