导航栏中的访问匹配对象 - React,Redux和TypeScript

时间:2017-09-29 07:57:55

标签: reactjs typescript redux react-router

我需要导航栏上的匹配对象。我正在使用React,Redux和TypeScript。

这是我的启动客户端文件:

    import './css/site.css';
    import 'bootstrap';
    import * as React from 'react';
    import * as ReactDOM from 'react-dom';
    import { AppContainer } from 'react-hot-loader';
    import { Provider } from 'react-redux';
    import { ConnectedRouter } from 'react-router-redux';
    import { createBrowserHistory } from 'history';
    import configureStore from './configureStore';
    import { ApplicationState } from './store/initialState';
    import * as RoutesModule from './routes';
    let routes = RoutesModule.routes;

    // Create browser history to use in the Redux store
    const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href')!;
    const history = createBrowserHistory({ basename: baseUrl });

    // Get the application-wide store instance, prepopulating with state from the server where available.
    const initialState = (window as any).initialReduxState as ApplicationState;
    const store = configureStore(history, initialState);

    function renderApp() {
        // This code starts up the React app when it runs in a browser. It sets up the routing configuration
        // and injects the app into a DOM element.
        ReactDOM.render(
            <AppContainer>
                <Provider store={ store }>
                    <ConnectedRouter history={ history } children={ routes } />
                </Provider>
            </AppContainer>,
            document.getElementById('react-app')
        );
    }

    renderApp();

    // Allow Hot Module Replacement
    if (module.hot) {
        module.hot.accept('./routes', () => {
            routes = require<typeof RoutesModule>('./routes').routes;
            renderApp();
        });
    }

This is my boot-server file:



  import * as React from 'react';
    import { Provider } from 'react-redux';
    import { renderToString } from 'react-dom/server';
    import { StaticRouter } from 'react-router-dom';
    import { replace } from 'react-router-redux';
    import { createMemoryHistory } from 'history';
    import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
    import { routes } from './routes';
    import configureStore from './configureStore';

    export default createServerRenderer(params => {
        return new Promise<RenderResult>((resolve, reject) => {
            // Prepare Redux store with in-memory history, and dispatch a navigation event
            // corresponding to the incoming URL
            const basename = params.baseUrl.substring(0, params.baseUrl.length - 1); // Remove trailing slash
            const urlAfterBasename = params.url.substring(basename.length);
            const store = configureStore(createMemoryHistory());
            store.dispatch(replace(urlAfterBasename));

            // Prepare an instance of the application and perform an inital render that will
            // cause any async tasks (e.g., data access) to begin
            const routerContext: any = {};
            const app = (
                <Provider store={ store }>
                    <StaticRouter basename={ basename }
                                  context={ routerContext }
                                  location={ params.location.path }
                                  children={ routes } />
                </Provider>
            );
            renderToString(app);

            // If there's a redirection, just send this information back to the host application
            if (routerContext.url) {
                resolve({ redirectUrl: routerContext.url });
                return;
            }

            // Once any async tasks are done, we can perform the final render
            // We also send the redux store state, so the client can continue execution where the server left off
            params.domainTasks.then(() => {
                resolve({
                    html: renderToString(app),
                    globals: { initialReduxState: store.getState() }
                });
            }, reject); // Also propagate any errors back into the host application
        });
    });  

这是布局文件:

    import * as React from 'react';
import {RouteComponentProps} from 'react-router-dom';
import {withRouter} from 'react-router';
import {connect} from 'react-redux';
import * as actions from '../Features/LanguageChanger/actions/languageChanger';
import LayoutProps from '../propertyTypes/LayoutProps';
import {ApplicationState} from '../store/initialState';
import Navbar from '../Features/Navbar/Navbar';
import NavbarContainer from '../containers/NavbarContainer';

class Layout extends React.Component<LayoutProps, {}> {
    public render() {
        return <div className='main-container'>
                <NavbarContainer {...this.props}/>
                {this.props.children}
        </div>;
    }
}

export default withRouter(connect(
    (state: ApplicationState) => state.language,
    actions.actionCreators,
)(Layout));

路线档案:

 import * as React from 'react';
import {Route} from 'react-router-dom';
import {Switch} from 'react-router';
import {Redirect} from 'react-router';
import Layout from './components/Layout';
import Home from './Features/Home/Home';
import About from './Features/About/About';
import ProductInfo from './Features/ProductInfo/ProductInfo';
import Questions from './Features/Questions/Questions';
import Shop from './Features/Shop/Shop';
import Contacts from './Features/Contacts/Contacts';

export const routes =
    <Layout>
            <Switch>
                <Route path='/:language/about' component={About}/>
                <Route path='/:language/product-info' component={ProductInfo}/>
                <Route path='/:language/questions' component={Questions}/>
                <Route path='/:language/shop' component={Shop}/>
                <Route path='/:language/contact-us' component={Contacts}/>
                <Route path='/:language' component={Home}/>
                <Route path='/' component={() => (<Redirect to={'/en'}/>)}/>
            </Switch>
    </Layout>;

我需要匹配对象,因为我需要根据URL中的语言发出请求。我的languageChanger组件位于Navbar中。我解决这个问题的方法是从URL中手动提取我所拥有的东西。有没有人有同样的问题?

1 个答案:

答案 0 :(得分:3)

要在组件中获取正确的路径道具,您应该使用withRouter

包裹connect
export default connect(/* ... */)(withRouter(Layout);

如果位置发生变化且connect未阻止,则会更新您的组件。 (您可以在React Router documentation

中了解更多信息

要从路径中获取占位符:langauge,必须将组件包装在具有path属性模式的路径组件中。

您的Layout组件内部:

/* ... */
return (
    <div className='main-container'>
        <Router path="/:language" render={({ match ) => (
            <NavbarContainer {...this.props} language={match.params.language} />
        )} />
        {this.props.children}
    </div>;
);
/* ... */

这样,导航栏只有在与路径模式匹配时才会被渲染。您可以将render更改为children,但之后您必须处理可能的匹配项,即null。 React Router对Route的可能性documentation有一个很好的enter image description here

无论如何,您必须确保match.params.language的值是真正的语言代码,因为有人可以在地址栏中输入路径/foo,您的语言将为foo。< / p>