reactjs react-router-dom - التنقل برمجيا باستخدام جهاز التوجيه رد فعل




12 Answers

React Router v4

مع الإصدار 4 من React Router ، هناك ثلاثة طرق يمكنك اتباعها للتوجيه البرمجي داخل المكونات.

  1. استخدم مع withRouter الأعلى من الترتيب.
  2. استخدم التكوين وقم بعرض <Route>
  3. استخدم context .

React Router هو في الغالب غلاف حول مكتبة history . history يعالج التفاعل مع window.history المتصفح بالنسبة لك مع تاريخ المستعرض والتاريخ. كما يوفر أيضًا محفوظات ذاكرة مفيدة للبيئات التي لا تحتوي على محفوظات عمومية. هذا مفيد بشكل خاص في تطوير تطبيقات الجوال ( react-native ) واختبار الوحدة مع عقدة.

لدى مثيل محفوظ طريقتين للتنقل: push replace . إذا كنت تفكر في history كمجموعة من المواقع التي تمت زيارتها ، push موقعًا جديدًا إلى الصفيف replace استبدال الموقع الحالي في الصفيف الجديد. عادةً ما ستحتاج إلى استخدام طريقة push أثناء التنقل.

في الإصدارات السابقة من React Router ، كان عليك إنشاء مثيل history خاص بك ، ولكن في v4 <BrowserRouter> و <HashRouter> و <MemoryRouter> بإنشاء مثيلات المتصفح <MemoryRouter> والذاكرة نيابة عنك. يجعل React Router خصائص وأساليب مثيل history المرتبطة بالموجه الخاص بك متاحة من خلال السياق ، تحت كائن router .

1. استخدم withRouter الأعلى من الترتيب

withRouter الأعلى من الترتيب مع كائن history كدعم للمكون. هذا يسمح لك بالوصول إلى push replace الأساليب دون الحاجة إلى التعامل مع context .

import { withRouter } from 'react-router-dom'
// this also works with react-router-native

const Button = withRouter(({ history }) => (
  <button
    type='button'
    onClick={() => { history.push('/new-location') }}
  >
    Click Me!
  </button>
))

2. استخدم التكوين وعرض <Route>

لا يعد المكون <Route> للمواقع المتطابقة فقط. يمكنك عرض مسار بلا مسار وسيتطابق دائمًا مع الموقع الحالي . يمر المكون <Route> بنفس الدعائم كما هو withRouter مع withRouter ، لذلك ستتمكن من الوصول إلى طرق history خلال دعم history .

import { Route } from 'react-router-dom'

const Button = () => (
  <Route render={({ history}) => (
    <button
      type='button'
      onClick={() => { history.push('/new-location') }}
    >
      Click Me!
    </button>
  )} />
)

3. استخدم السياق *

* ولكن ربما لا ينبغي لك

الخيار الأخير هو الذي يجب عليك استخدامه فقط إذا كنت تشعر بالراحة في العمل مع نموذج context React. على الرغم من أن السياق هو أحد الخيارات ، إلا أنه يجب التأكيد على أن السياق عبارة عن واجهة برمجة تطبيقات غير مستقرة و React يحتوي على قسم لماذا لا يستخدم السياق في وثائقهم. لذلك استخدام على مسؤوليتك الخاصة!

const Button = (props, context) => (
  <button
    type='button'
    onClick={() => {
      // context.history.push === history.push
      context.history.push('/new-location')
    }}
  >
    Click Me!
  </button>
)

// you need to specify the context type so that it
// is available within the component
Button.contextTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  })
}

1 و 2 هما أبسط الخيارات لتنفيذ ، لذلك بالنسبة لمعظم حالات الاستخدام فهي أفضل رهاناتك.

v4 tutorial

باستخدام react-router يمكنني استخدام عنصر Link لإنشاء روابط يتم التعامل معها أصلاً بواسطة جهاز التوجيه المتفاعل.

أرى داخليا أنه يدعو هذا. this.context.transitionTo(...) .

أريد إجراء التنقل ، ولكن ليس من رابط ، من تحديد القائمة المنسدلة على سبيل المثال. كيف يمكنني القيام بذلك في الكود؟ ما هو this.context .

رأيت مزيج Navigation ، ولكن هل يمكنني القيام بذلك دون خلط؟




React-Router v2

بالنسبة لأحدث إصدار ( v2.0.0-rc5 ) ، فإن طريقة التنقل الموصى بها هي من خلال الضغط مباشرة على مفردة المفردات. يمكنك رؤية ذلك في الإجراء في وثيقة التنقل خارج وثيقة المكونات .

مقتطف ذو صلة:

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

إذا كنت تستخدم واجهة برمجة تطبيقات التفاعل-الموجه الأحدث ، فستحتاج إلى استخدام history من this.props عندما تكون داخل المكونات بحيث:

this.props.history.push('/some/path');

كما أنه يوفر pushState ولكن هذا هو pushState لكل التحذيرات المسجلة.

في حالة استخدام react-router-redux ، فإنه يوفر وظيفة push يمكنك إرسالها على النحو التالي:

import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

ومع ذلك ، يمكن استخدام هذا فقط لتغيير عنوان URL ، وليس للانتقال فعليًا إلى الصفحة.




لهذا واحد ، الذي لا يتحكم في جانب الخادم وبسبب هذا يستخدم جهاز التوجيه جهاز التوجيه V2:

ضع history في ملف منفصل (على سبيل المثال app_history.js ES6):

import { useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false });

export default appHistory;

واستخدامها في كل مكان!

نقطة الإدخال الخاصة بك لموجه الاستجابة (app.js ES6):

import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Redirect } from 'react-router'
import appHistory from './app_history'
...
const render((
  <Router history={appHistory}>
  ...
  </Router>
), document.querySelector('[data-role="app"]'));

التنقل داخل أي مكون (ES6):

import appHistory from '../app_history'
...
ajaxLogin('/login', (err, data) => {
  if (err) {
    console.error(err); // login failed
  } else {
    // logged in
    appHistory.replace('/dashboard'); // or .push() if you don't need .replace()
  }
})



حاولت على الأقل 10 طرق للقيام بذلك قبل أن يعمل شيء على حق!

Felipe Skinner's withRouter answer was a withRouter to me، and not withRouter to make new "ExportedWithRouter" class name.

إليك الطريقة الأبسط والأكثر أنظافًا لفعل ذلك ، حول circa الحالي React-Router 3.0.0 و ES6:

رد الفعل الموجه 3.xx مع ES6:

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
export default withRouter(Example);

أو ، إذا لم يكن صفك الافتراضي ، فقم بالتصدير مثل:

withRouter(Example);
export { Example };

لاحظ أنه في router.push ، يستخدم المكون <Link> نفسه router.push ، بحيث يمكنك تمرير أي شيء قد تمر <Link to= tag ، مثل:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'



بالنسبة لمكونات ES6 + React ، يعمل الحل التالي بالنسبة لي.

تابعت فيليبي سكينر ، لكنها أضافت حلا نهائيا لمساعدة المبتدئين مثلي.

فيما يلي الإصدارات التي استخدمتها:

"موجه التوجيه": "^ 2.7.0"

"رد": "^ 15.3.1"

يوجد أدناه مكون رد الفعل الخاص بي حيث استخدمت التنقل البرمجي باستخدام react-router:

import React from 'react';

class loginComp extends React.Component {
   constructor( context) {
    super(context);
    this.state = {
      uname: '',
      pwd: ''
    };
  }

  redirectToMainPage(){
        this.context.router.replace('/home');
  }

  render(){
    return <div>
           // skipping html code 
             <button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
    </div>;
  }
};

 loginComp.contextTypes = {
    router: React.PropTypes.object.isRequired
 }

 module.exports = loginComp;

فيما يلي التكوين الخاص بالموجه:

 import { Router, Route, IndexRedirect, browserHistory } from 'react-router'

 render(<Router history={browserHistory}>
          <Route path='/' component={ParentComp}>
            <IndexRedirect to = "/login"/>
            <Route path='/login' component={LoginComp}/>
            <Route path='/home' component={HomeComp}/>
            <Route path='/repair' component={RepairJobComp} />
            <Route path='/service' component={ServiceJobComp} />
          </Route>
        </Router>, document.getElementById('root'));



للقيام بالملاحة برمجياً ، تحتاج إلى دفع محفوظات جديدة إلى props.history في component الخاص بك ، بحيث يمكن القيام بشيء مثل هذا العمل لك:

//using ES6
import React from 'react';

class App extends React.Component {

  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(e) {
    e.preventDefault()
    /* Look at here, you can add it here */
    this.props.history.push('/redirected');
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Redirect!!!
        </button>
      </div>
    )
  }
}

export default App;



React Router V4

TL: الدكتور.

if (navigate) {
  return <Redirect to="/" push={true} />
}

الإجابة البسيطة والتصريحية هي أنك تحتاج إلى استخدام <Redirect to={URL} push={boolean} /> بالاشتراك مع setState()

push: boolean - عندما يكون true ، سيؤدي إعادة التوجيه إلى إدخال إدخال جديد على السجل بدلاً من استبدال السجل الحالي.

import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

المثال الكامل here . اقرأ المزيد here .

PS. يستخدم المثال Initializers خاصية ES7 + في تهيئة الحالة. انظر here أيضا ، إذا كنت مهتما.




مع React-Router v4 في الأفق ، هناك الآن طريقة جديدة للقيام بذلك.

import { MemoryRouter, BrowserRouter } from 'react-router';

const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;

<Router location="/page-to-go-to"/>

react-lego هو تطبيق مثال يوضح كيفية استخدام / تحديث جهاز التوجيه المتفاعل ويتضمن أمثلة على الاختبارات الوظيفية التي تنقل التطبيق.




مع إصدار this.props.history.push('/location'); الحالي (15.3) ، this.props.history.push('/location'); عملت لي ، لكنها أظهرت التحذير التالي:

browser.js: 49 تحذير: تم إهمال [react-router] props.history و context.history . يرجى استخدام context.router .

وأنا حلها باستخدام context.router مثل هذا:

import React from 'react';

class MyComponent extends React.Component {

    constructor(props) {
        super(props);
        this.backPressed = this.backPressed.bind(this);
    }

    backPressed() {
        this.context.router.push('/back-location');
    }

    ...
}

MyComponent.contextTypes = {
    router: React.PropTypes.object.isRequired
};

export default MyComponent;



كان الجواب الصحيح بالنسبة لي في وقت كتابة هذا التقرير

this.context.router.history.push('/');

ولكن تحتاج إلى إضافة PropTypes إلى المكون الخاص بك

Header.contextTypes = {
  router: PropTypes.object.isRequired
}
export default Header;

لا تنسَ استيراد PropTypes

import PropTypes from 'prop-types';



ربما ليس الحل الأفضل ولكنه ينجز المهمة:

import { Link } from 'react-router-dom';

// create functional component Post
export default Post = () => (
    <div className="component post">

        <button className="button delete-post" onClick={() => {
            // ... delete post
            // then redirect, without page reload, by triggering a hidden Link
            document.querySelector('.trigger.go-home').click();
        }}>Delete Post</button>

        <Link to="/" className="trigger go-home hidden"></Link>

    </div>
);

في الأساس ، فإن المنطق المرتبط بإجراء واحد (في هذه الحالة حذف النشر) سينتهي في النهاية بالاتصال بمحفز لإعادة التوجيه. هذا ليس مثاليًا لأنك ستضيف "عقدة" لعقدة DOM إلى ترميزك حتى تتمكن من الاتصال بها بسهولة عند الحاجة. أيضا ، سوف تتفاعل مباشرة مع DOM ، والتي في مكون React قد لا تكون مرغوبة.

لا يزال ، هذا النوع من إعادة التوجيه غير مطلوب في كثير من الأحيان. إذاً ، لن يكون هناك ارتباط أو رابطان إضافيان مخفيان في ترميز المكون الخاص بك لن يؤذي ذلك كثيرًا ، خاصة إذا أعطيتهما أسماء ذات معنى.




يمكنك التوجيه إلى مكون آخر بهذه الطريقة.

toProfile() {
   this.context.history.pushState(null, 'profile');
}

وإضافة onClickوظيفة

<li onClick={this.toProfile.bind(this)></li>

آمل أن يكون مفيدا بالنسبة لك.




Related

reactjs react-router