私は数ヶ月の経験に反応するのは初めてです。動的ルートを実装する必要があるこのプロジェクトに取り組んでいます。そのために、このroute.js
ファイルを使用しています。
// These are the pages you can go to.
// They are all wrapped in the App component, which should contain the navbar etc
// See http://blog.mxstbr.com/2016/01/react-apps-with-pages for more information
// about the code splitting business
import { getAsyncInjectors } from 'utils/asyncInjectors';
import App from 'containers/App';
const errorLoading = (err) => {
console.error('Dynamic page loading failed', err); // eslint-disable-line no-console
};
const loadModule = (cb) => (componentModule) => {
cb(null, componentModule.default);
};
function createChildRoutes(store) {
// create reusable async injectors using getAsyncInjectors factory
const { injectReducer, injectSagas } = getAsyncInjectors(store); // eslint-disable-line no-unused-vars
let previousPath = null;
return [
{
path: '/',
getComponent(nextState, cb) {
if (nextState.location.pathname === previousPath) {
return;
}
const importModules = Promise.all([
import('containers/HomePage/reducer'),
import('containers/App/sagas'),
import('containers/HomePage/sagas'),
import('containers/HomePage'),
]);
const renderRoute = loadModule(cb);
importModules.then(([reducer, appSagas, sagas, component]) => {
injectReducer('homePage', reducer.default);
injectSagas([...appSagas.default, ...sagas.default]);
renderRoute(component);
});
importModules.catch(errorLoading);
previousPath = nextState.location.pathname;
},
},
{
path: '/:urlKey',
getComponent(nextState, cb) {
if (nextState.location.pathname === previousPath) {
return;
}
const importModules = Promise.all([
import('containers/CatalogPage/actions'),
import('containers/CatalogPage/reducer'),
import('containers/App/sagas'),
import('containers/CatalogPage/sagas'),
import('containers/CatalogPage'),
]);
const renderRoute = loadModule(cb);
importModules.then(([actions, reducer, appSagas, sagas, component]) => {
injectReducer('catalogPage', reducer.default);
injectSagas([...appSagas.default, ...sagas.default]);
renderRoute(component);
store.dispatch(actions.loadPageData(nextState.params.urlKey));
});
importModules.catch(errorLoading);
previousPath = nextState.location.pathname;
},
}, {
path: '*',
getComponent(nextState, cb) {
import('containers/NotFoundPage')
.then(loadModule(cb))
.catch(errorLoading);
},
},
];
}
// Set up the router, wrapping all Routes in the App component
export default function createRootRoute(store) {
return {
component: App,
childRoutes: createChildRoutes(store),
};
}
このpath: '/:urlKey'
コンポーネントにインポートされ、これを使用this.props.loadPageData(this.props.params.urlKey);
してアクションをディスパッチcomponentWillMount()
し、ルートの ssr を有効にします。カタログ コンポーネントからのルーティングを有効にするために、アクションroutes.js
もディスパッチする必要がありました。
私のコンポーネントファイルcoatalog.js
/* eslint no-tabs: "off", no-trailing-spaces: "off", indent: "off", react/jsx-indent: "off", react/jsx-indent-props: "off" */
/*
*
* CatalogPage - this will handle conditions for page type and route the data to their specific components.
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Helmet } from 'react-helmet';
import { createStructuredSelector } from 'reselect';
// import PageWrapperContainer from 'components/PageWrapperContainer';
import CategoryPages from 'components/CategoryPages';
import ProductDetailsPages from 'components/ProductDetailsPages';
import { deviceTypeSelect, isMobileSelect, atcLoaderStateSelect } from 'containers/App/selectors';
import { addToCart } from 'containers/App/actions';
import { loadPageData, getCurrentCategoryState } from './actions';
import { pageDataSelect,
currentCategoryStateSelect,
metaTitleSelect,
metaDescriptionSelect,
pageTypeSelect,
contentTypeSelect,
pageHeadingSelect,
pageSubheadingSelect,
selectAppLoading } from './selectors';
export class CatalogPage extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
componentWillMount() {
// dispatching the urlKey
this.props.loadPageData(this.props.params.urlKey);
}
render() {
const { metaTitle,
metaDescription,
pageType,
contentType,
categoryPageHeading,
categoryPageSubHeading,
pageData,
appLoading } = this.props;
// console.log(this.props);
return (
<div>
<Helmet>
<title>{metaTitle}</title>
<meta name="description" content={metaDescription} />
</Helmet>
{(appLoading !== false) ? <p>Loading.....</p> : null}
{ ((appLoading !== true) && (pageType === 'category')) ?
<CategoryPages
pageData={pageData}
contentType={contentType}
categoryPageHeading={categoryPageHeading}
categoryPageSubHeading={categoryPageSubHeading}
currentCategoryState={this.props.currentCategoryState}
getCurrentCategoryState={this.props.getCurrentCategoryState}
deviceTypeSelect={this.props.deviceTypeSelect}
isMobileSelect={this.props.isMobileSelect}
atcLoaderStateSelect={this.props.atcLoaderStateSelect}
addToCart={this.props.addToCart}
/>
: null
}
{ ((appLoading !== true) && (pageType === 'product')) ?
<ProductDetailsPages
pageData={pageData}
contentType={contentType}
deviceTypeSelect={this.props.deviceTypeSelect}
isMobileSelect={this.props.isMobileSelect}
atcLoaderStateSelect={this.props.atcLoaderStateSelect}
addToCart={this.props.addToCart}
/>
: null
}
</div>
);
}
}
CatalogPage.propTypes = {
params: PropTypes.object,
urlKey: PropTypes.string,
loadPageData: PropTypes.func,
pageData: PropTypes.oneOfType([
PropTypes.object,
PropTypes.any,
]),
currentCategoryState: PropTypes.string,
getCurrentCategoryState: PropTypes.func,
metaTitle: PropTypes.string,
metaDescription: PropTypes.string,
pageType: PropTypes.string,
contentType: PropTypes.string,
categoryPageHeading: PropTypes.string,
categoryPageSubHeading: PropTypes.string,
appLoading: PropTypes.bool,
deviceTypeSelect: PropTypes.string,
isMobileSelect: PropTypes.bool,
atcLoaderStateSelect: PropTypes.any,
addToCart: PropTypes.func,
};
const mapStateToProps = createStructuredSelector({
pageData: pageDataSelect(),
currentCategoryState: currentCategoryStateSelect(),
metaTitle: metaTitleSelect(),
metaDescription: metaDescriptionSelect(),
pageType: pageTypeSelect(),
contentType: contentTypeSelect(),
categoryPageHeading: pageHeadingSelect(),
categoryPageSubHeading: pageSubheadingSelect(),
appLoading: selectAppLoading(),
deviceTypeSelect: deviceTypeSelect(),
isMobileSelect: isMobileSelect(),
atcLoaderStateSelect: atcLoaderStateSelect(),
});
function mapDispatchToProps(dispatch) {
return {
loadPageData: bindActionCreators(loadPageData, dispatch),
getCurrentCategoryState: bindActionCreators(getCurrentCategoryState, dispatch),
addToCart: bindActionCreators(addToCart, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(CatalogPage);
これに関する私の問題は、パスの最初のレンダリングでlocalhost:3000/:urlKey
、アクションを2回ディスパッチしているため、コンポーネントが2回componentWillMount()
レンダリングされることですroutes.js
。routes.js
このコードを改善して、アプリの最初の読み込みからのアクションのディスパッチをブロックすることでコンポーネントの再レンダリングを停止するには、助けが必要です。