React-intl 在 Safari v8.0.8 上禁用 react-router 的 Link 组件 onClick 事件

Posted

技术标签:

【中文标题】React-intl 在 Safari v8.0.8 上禁用 react-router 的 Link 组件 onClick 事件【英文标题】:React-intl disable react-router's Link component onClick event on Safari v8.0.8 【发布时间】:2017-01-05 22:39:36 【问题描述】:

我正在开发一个在服务器端和客户端呈现的反应通用应用程序。该应用程序在 Chrome 上运行 #1,但在 Safari 上,react-router 的 Link 只是重新渲染整个应用程序并执行 http 请求。

应用程序可以正确呈现,但是当它在 Chrome 中完美运行时,链接不会在 Safari 中进行转换。

这是我的 routing.js 文件,它是一个 expressjs 中间件

    import React from 'react';
    import  trigger  from 'redial';
    import createMemoryHistory from 'history/lib/createMemoryHistory';
    import useQueries from 'history/lib/useQueries';
    import  match, RouterContext  from 'react-router';
    import  Provider  from 'react-redux';
    import  createStore, applyMiddleware  from 'redux';

    import  thunkMiddleware  from './thunkMiddleware';
    import reducers from 'reducers';
    import routes from '../routes';

    const store = applyMiddleware(thunkMiddleware)(createStore)(reducers);
    const  dispatch  = store;

    function getRootComponent(renderProps) 
      const state = store.getState();

      const component = (
        <Provider store=store>
          <RouterContext ...renderProps />
        </Provider>
      );

      return 
        component,
        initialState: state,
      ;
    

    function routing(req, res) 
      const history = useQueries(createMemoryHistory)();
      const location = history.createLocation(req.url);

      return new Promise((resolve, reject) => 
        match( routes, location , (error, redirectLocation, renderProps) => 
          // Get array of route components:
          const components = renderProps.routes.map(route => route.component);
          // Define locals to be provided to all fetcher functions:
          const locals = 
            path: renderProps.location.pathname,
            query: renderProps.location.query,
            params: renderProps.params,
            cookies: req.cookies,
            // Allow fetcher functions to dispatch Redux actions:
            dispatch,
          ;

          if (typeof req.cookies.user_token === 'undefined' && (req.url !== '/login')) 
            res.status(301).redirect('/login');
           else 
            if (redirectLocation) 
              reject(res.status(301).redirect(redirectLocation.pathname + redirectLocation.search));
             else if (error) 
              reject(res.status(500).send(error.message));
             else if (renderProps === null) 
              reject(res.status(404).send('Not found'));
            

            // trigger l'action de "redial"
            trigger('fetch', components, locals)
              .then((cookieValues) => 
                let cookieTime = 3600000; // 1 heure

                if (typeof cookieValues !== 'undefined' && typeof cookieValues[0] !== 'undefined') 
                  if (typeof req.cookies.remember_me !== 'undefined') 
                    cookieTime = 1296000000; // 15 jours
                    res.cookie('remember_me', true,  maxAge: cookieTime, httpOnly: false );
                  

                  res.cookie('user_loggedIn', cookieValues[0].user_loggedIn,  maxAge: cookieTime, httpOnly: false );
                  res.cookie('user_id', cookieValues[0].user_id,  maxAge: cookieTime, httpOnly: false );
                  res.cookie('user_token', cookieValues[0].user_token,  maxAge: cookieTime, httpOnly: false );
                

                resolve(getRootComponent(renderProps));
              )
              .catch(reject);
          
        );
      );
    

    export default routing;

这是我用于客户端渲染的app.js

history.listen(() => 
  // Match routes based on location object:
  match( history, routes , (routerError, redirectLocation, renderProps) => 
    console.log(routerError, redirectLocation, renderProps);
    // Check si renderProps est true sinon c'est un redirect
    if (renderProps) 
      // Get array of route components:
      const components = renderProps.routes.map(route => route.component);

      // Define locals to be provided to all lifecycle hooks:
      const locals = 
        path: renderProps.location.pathname,
        query: renderProps.location.query,
        params: renderProps.params,
        state: store.getState(),
        // Allow lifecycle hooks to dispatch Redux actions:
        dispatch,
      ;

      // Fetch deferred, client-only data dependencies
      trigger('defer', components, locals)
        // Finally, trigger 'done' lifecycle hooks:
        .then(() => 
          const state = store.getState();

          // checkIfFormIsCompleted(location, state, () => 
          renderApplication();

          trigger('done', components,  ...locals, state );
          // );
        );
    

    function renderApplication() 
      ReactDOM.render((
        <Provider store=store>
          <Router history=history>routes</Router>
        </Provider>
      ), document.getElementById(APP_DOM_CONTAINER));
    
  );
);

当我console.log 两者兼而有之时,一切都很好。没有错误,服务器和客户端都没有错误。链接只是不想触发历史更改并进行应用程序更改。

如果重要的话,我也使用 react-router-redux,我只是更新了软件包只是为了检查它们是否可以工作,但没有任何改变。

"react": "^15.1.0",
"react-router": "^2.7.0",
"react-router-redux": "^4.0.0",
"redux": "^3.0.6",
"redux-form": "^5.2.4",

我刚刚深入研究了 DOM 以查看点击事件是如何绑定的,我看到 Safari 中的链接错过了来自 ReactEventListener.js 的事件。

http://imgur.com/a/GA7bI

感谢您的帮助!

【问题讨论】:

您使用的是旧版本的 Safari 吗? History API 应该支持 5+ github.com/browserstate/history.js/wiki/… 我正在使用版本 8.0.8 imgur.com/eCGNxGn 【参考方案1】:

您好,必须将此 polyfill 脚本添加到我的 html 页面。

<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.fr,Intl.~locale.en" />

之后,一切正常!我工作的 iMac 上没有控制台错误或任何东西,但在我的笔记本电脑上,控制台出现错误。

您可以在此处查看更多信息:

http://formatjs.io/github/#polyfills

【讨论】:

以上是关于React-intl 在 Safari v8.0.8 上禁用 react-router 的 Link 组件 onClick 事件的主要内容,如果未能解决你的问题,请参考以下文章

在 Safari 中重叠 CSS flexbox 项目

用酶测试 react-intl 组件

react-intl - 访问嵌套消息

React-intl 在 react 之外定义消息

在 Redux 中间件中使用 React-intl 翻译的消息

react-intl 货币显示不带小数