前提・実現したいこと
ReduxとRedux Sagaを使ったSPAでアプリ全体で使うstateを1箇所で管理したいです。
使用しているミドルウェアなど
- react:16.12.0
- react-redux": "^7.1.3",
- "redux-saga": "^1.1.3
発生している問題・エラーメッセージ
teratailのような通知をRedux storeのstateで管理する場合、通知を取得するメソッドを各ContainerやComponentに記述しなければならない。
現状のソースコード
本当はログイン情報処理を1つにまとめたいのですが、以下のように各Containerにメソッドを書いて、 componentDidMount()
などで呼び出しております。
Container
js
1import { connect } from 'react-redux' 2import * as actions from '../actions/index'; 3import Home from '../components/home' 4 5const mapStateToProps = state => { 6 return { 7 trips: state.indexReducer.trips, 8 popularTrips: state.indexReducer.popularTrips, 9 latestTrips: state.indexReducer.latestTrips, 10 lng: state.indexReducer.lng, 11 showModal: state.indexReducer.showModal, 12 showQuestionModal: state.indexReducer.showQuestionModal, 13 showSlideMenu: state.indexReducer.showSlideMenu, 14 showSearchMenu: state.indexReducer.showSearchMenu, 15 userinfo: state.indexReducer.userinfo, 16 loginInfo: state.indexReducer.loginInfo, 17 } 18} 19 20 21const mapDispatchToProps = dispatch => { 22 return { 23 getTrips: (lng) => dispatch(actions.getTrips(lng)), 24 getTripsSuccess: (trips) => dispatch(actions.getTripsSuccess(trips)), 25 getPopularTrips: (lng) => dispatch(actions.getPopularTrips(lng)), 26 getPopularTripsSuccess: (trips) => dispatch(actions.getPopularTripsSuccess(trips)), 27 getLatestTrips: (lng) => dispatch(actions.getLatestTrips(lng)), 28 getLatestTripsSuccess: (trips) => dispatch(actions.getLatestTripsSuccess(trips)), 29 langChange: (lng, path, args) => dispatch(actions.langChange(lng, path, args)), 30 openModal: () => dispatch(actions.openModal()), 31 closeModal: () => dispatch(actions.closeModal()), 32 openQuestionModal: () => dispatch(actions.openQuestionModal()), 33 closeQuestionModal: () => dispatch(actions.closeQuestionModal()), 34 openSlideMenu: () => dispatch(actions.openSlideMenu()), 35 closeSlideMenu: () => dispatch(actions.closeSlideMenu()), 36 openSearchMenu: () => dispatch(actions.openSearchMenu()), 37 closeSearchMenu: () => dispatch(actions.closeSearchMenu()), 38 receiveResult: result => dispatch(actions.receiveResult(result)), 39 // 未読お知らせ 40 receiveUnreadNotices: () => dispatch(actions.receiveUnreadNotices()), 41 receiveUnreadNoticesSuccess: notices => dispatch(actions.receiveUnreadNoticesSuccess(notices)), 42 } 43} 44 45const HomeContainer = connect(mapStateToProps, mapDispatchToProps)(Home); 46export default HomeContainer
component
js
1import HomeSearch from './home/search'; 2import GetApp from "./statics/getApp" 3import GetPcApp from "./statics/getPcApp" 4import QuestionModal from "./question/postModal" 5 6import '../css/_swiper.scss' 7 8class Home extends Component { 9 componentDidMount = async () => { 10 this.props.getTrips(this.props.lng) 11 this.props.getPopularTrips(this.props.lng) 12 this.props.receiveUnreadNotices() 13 await this.props.getLatestTrips(this.props.lng) 14 const timezone = await Api.getUserLocation(); 15 // クッキーに言語設定がない、かつユーザーの位置情報取れたら 16 if (!cookie.load('i18next') && !timezone.country.match(/JP/)) { 17 this.props.langChange('en') 18 } else { 19 this.props.langChange('jp') 20 } 21 } 22 23 render() { 24 // 最新旅行のパネル 25 let featured = [] 26 featured = homeSwipers.featured(this.props) 27 // 人気旅行のパネル 28 let populars = []
該当のソースコード
App.js
javascript
1// React Router File 2import React from 'react' 3import { Route, Switch } from 'react-router-dom' 4import ReactGA from 'react-ga' 5 6// 各コンテナへ 7import HomeContainer from './containers/Home' 8import SpotContainer from './containers/Spot' 9import TripContainer from './containers/Trip' 10import StaticCotainer from './containers/Static' 11import ContactContainer from './containers/Contact' 12import ResultContainer from './containers/Result' 13import SigninContainer from './containers/Signin' 14import MypageContainer from './containers/Mypage' 15import CreateTripContainer from './containers/CreateTrip' 16import MypageModifyContainer from './containers/MypageModify' 17import UserinfoContainer from './containers/UserInfo' 18import UserInfoChangeContainer from './containers/UserInfoChange' 19import NotFound from './components/NotFound' 20 21export const App = (history) => { 22 // Google Analitics 23 const { pathname } = history.history.location.pathname 24 ReactGA.initialize(process.env.REACT_APP_ANALYTICS) 25 ReactGA.set({ page: pathname }) 26 ReactGA.pageview(history.history.location.pathname) 27 return ( 28 <Switch> 29 <Route exact path="/" component={HomeContainer} /> 30 <Route path="/spot/:id" component={SpotContainer} /> 31 <Route path="/trip/create/" component={CreateTripContainer} /> 32 <Route path="/trip/:id" component={TripContainer} /> 33 <Route path="/result/:keyword" component={ResultContainer} /> 34 <Route path="/mypage/" component={MypageContainer} /> 35 <Route path="/modify/mypage" component={MypageModifyContainer} /> 36 <Route path="/userinfo/" component={UserinfoContainer} /> 37 <Route path="/email_change/" component={UserInfoChangeContainer} /> 38 <Route path="/password_change/" component={UserInfoChangeContainer} /> 39 {/* Static Pages */} 40 <Route path="/signin" component={SigninContainer} /> 41 <Route path="/signup" component={SigninContainer} /> 42 <Route path="/contact" component={ContactContainer} /> 43 <Route path="/terms/free" component={StaticCotainer} /> 44 <Route path="/terms/privacy" component={StaticCotainer} /> 45 <Route component={NotFound} /> 46 </Switch> 47 ) 48}
createStore.js
js
1import { createStore as reduxCreateStore, applyMiddleware } from "redux" 2// consoleで表示されるログ 3import { createLogger } from "redux-logger" 4// rootReducerを作る関数 5import { createRootReducer } from './reducers/rootReducer' 6// routerの履歴関係 7import { createBrowserHistory } from 'history' 8import ReactGA from 'react-ga' 9import { routerMiddleware } from 'connected-react-router' 10// Saga 11import createSagaMiddleware from 'redux-saga'; 12import rootSaga from './sagas/index'; 13import { composeWithDevTools } from "redux-devtools-extension"; 14 15export const history = createBrowserHistory() 16ReactGA.initialize('UA-*******') 17history.listen(({ pathname }) => { 18 ReactGA.set({ page: pathname }) 19 ReactGA.pageview(pathname) 20}) 21export default function createStore() { 22 const sagaMiddleware = createSagaMiddleware() 23 const middlewares = [sagaMiddleware] 24 25 if (process.env.REACT_APP_ENV !== 'production') { 26 const logger = createLogger({ 27 diff: true, 28 collapsed: true, 29 }) 30 middlewares.push(logger); 31 } 32 const enhancer = 33 process.env.REACT_APP_ENV !== "production" 34 ? composeWithDevTools(applyMiddleware(...middlewares, routerMiddleware(history))) 35 : applyMiddleware(...middlewares, routerMiddleware(history)); 36 37 const store = reduxCreateStore( 38 createRootReducer(history), // root reducer with router state 39 enhancer, 40 ) 41 sagaMiddleware.run(rootSaga) 42 return store; 43}
index.js
js
1import React from 'react' 2import ReactDOM from 'react-dom' 3import * as serviceWorker from './serviceWorker' 4import './css/_notosans.scss' 5import { App } from './App' 6// react-redux-router関係 7import { Provider } from 'react-redux' 8import { ConnectedRouter } from 'connected-react-router' 9import createStore, { history } from './createStore' 10 11import { I18nextProvider } from 'react-i18next'; 12// 翻訳のindex.jsを読み込み 13import i18n from './i18n'; 14 15import 'bootstrap/dist/css/bootstrap.min.css'; 16// fontawesome 17import { library } from '@fortawesome/fontawesome-svg-core' //fontawesomeのコアファイル 18import { fab } from '@fortawesome/free-brands-svg-icons' //fontawesomeのbrandアイコンのインポート 19import { fas } from '@fortawesome/free-solid-svg-icons' //fontawesomeのsolidアイコンのインポート 20import { far } from '@fortawesome/free-regular-svg-icons' //他のコンポーネントから簡単に呼び出せるようにするための登録処理 21 22library.add(fab, fas, far); 23 24const store = createStore() 25 26ReactDOM.render( 27 <Provider store={store}> 28 <ConnectedRouter history={history}> 29 <I18nextProvider i18n={i18n}> 30 <App history={history} store={store} /> 31 </I18nextProvider> 32 </ConnectedRouter> 33 </Provider>, 34 document.getElementById('root') 35) 36
試したこと
index.jsでstoreの内容を取得して、App.jsに渡そうとしましたが、上手くいかずです。
index.js
js
1 2library.add(fab, fas, far); 3 4const store = createStore() 5 6ReactDOM.render( 7 <Provider store={store}> 8 <ConnectedRouter history={history}> 9 <I18nextProvider i18n={i18n}> 10 <App history={history} store={store} /> 11 </I18nextProvider> 12 </ConnectedRouter> 13 </Provider>, 14 document.getElementById('root') 15)
App.js
js
1 2export const App = (history, store) => { 3 // Google Analitics 4 console.log(history); 5 6 const { pathname } = history.history.location.pathname 7 ReactGA.initialize(process.env.REACT_APP_ANALYTICS) 8 ReactGA.set({ page: pathname }) 9 ReactGA.pageview(history.history.location.pathname) 10 return ( 11 <Switch> 12 <Route exact path="/" component={HomeContainer} /> 13 <Route path="/spot/:id" component={SpotContainer} /> 14 <Route path="/trip/create/" component={CreateTripContainer} /> 15 <Route path="/trip/:id" component={TripContainer} /> 16 <Route path="/result/:keyword" component={ResultContainer} /> 17 <Route path="/mypage/" component={MypageContainer} /> 18 <Route path="/modify/mypage" component={MypageModifyContainer} />
アプリが大きくなるに従い、共通情報の抜けなどが出そうで困っているため、何卒よろしくお願いいたします。
あなたの回答
tips
プレビュー