development

React Router v4에서 히스토리로 푸시하는 방법?

big-blog 2020. 3. 15. 09:39
반응형

React Router v4에서 히스토리로 푸시하는 방법?


React Router (v3)의 현재 버전에서는 서버 응답을 수락 browserHistory.push하고 적절한 응답 페이지로 이동하는 데 사용할 수 있습니다. 그러나 이것은 v4에서 사용할 수 없으며이를 처리하는 적절한 방법이 무엇인지 잘 모르겠습니다.

이 예에서 Redux를 사용 하면 사용자가 양식을 제출할 때 components / app-product-form.js가 호출 this.props.addProduct(props)됩니다. 서버가 성공하면 사용자는 카트 페이지로 이동합니다.

// actions/index.js
export function addProduct(props) {
  return dispatch =>
    axios.post(`${ROOT_URL}/cart`, props, config)
      .then(response => {
        dispatch({ type: types.AUTH_USER });
        localStorage.setItem('token', response.data.token);
        browserHistory.push('/cart'); // no longer in React Router V4
      });
}

React Router v4 기능에서 장바구니 페이지로 리디렉션하려면 어떻게해야합니까?


history컴포넌트 외부 에서 메소드 를 사용할 수 있습니다 . 다음과 같은 방법으로 시도하십시오.

먼저 history 패키지를history 사용 하는 객체를 만듭니다 .

// src/history.js

import { createBrowserHistory } from 'history';

export default createBrowserHistory();

그런 다음에 그것을 포장 <Router>( 하시기 바랍니다 참고 , 당신은 사용해야하는 import { Router }대신 import { BrowserRouter as Router }) :

// src/index.jsx

// ...
import { Router, Route, Link } from 'react-router-dom';
import history from './history';

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <div>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/login">Login</Link></li>
        </ul>
        <Route exact path="/" component={HomePage} />
        <Route path="/login" component={LoginPage} />
      </div>
    </Router>
  </Provider>,
  document.getElementById('root'),
);

예를 들어 다음과 같이 어느 곳에서나 현재 위치를 변경하십시오.

// src/actions/userActionCreators.js

// ...
import history from '../history';

export function login(credentials) {
  return function (dispatch) {
    return loginRemotely(credentials)
      .then((response) => {
        // ...
        history.push('/');
      });
  };
}

UPD : React Router FAQ 에서 약간 다른 예를 볼 수도 있습니다 .


React Router v4는 v3 (이전)와 근본적으로 다르므로 이전과 동일하게 사용할 수 없습니다 browserHistory.push().

정보는 더 많은 정보를 원한다면 관련 이있는 것 같습니다.

  • 자체 히스토리 인스턴스를 작성하고 해당 변경 사항을 청취 browserHistory하므로 새 작성은 작동하지 않습니다 <BrowserRouter>. 따라서 다른 인스턴스는 URL을 변경하지만을 업데이트하지는 않습니다 <BrowserRouter>.
  • browserHistory v4에서는 반응 라우터에 의해 노출되지 않으며 v2에서만 노출됩니다.

대신이 작업을 수행 할 수있는 몇 가지 옵션이 있습니다.

  • 사용 withRouter상위 구성 요소를

    대신 withRouter고차 컴포넌트를 사용하여 히스토리로 푸시 할 컴포넌트로 랩핑해야합니다. 예를 들면 다음과 같습니다.

    import React from "react";
    import { withRouter } from "react-router-dom";
    
    class MyComponent extends React.Component {
      ...
      myFunction() {
        this.props.history.push("/some/Path");
      }
      ...
    }
    export default withRouter(MyComponent);
    

    자세한 내용 공식 문서확인하십시오 .

    당신은에 액세스 얻을 수있는 history객체의 속성과 가장 가까운 <Route>matchwithRouter 고차원 적 요소를 통해입니다. withRouter는 <Route>렌더 소품 과 동일한 소품으로 경로가 변경 될 때마다 컴포넌트를 다시 렌더링합니다 { match, location, history }.


  • contextAPI 사용

    컨텍스트를 사용하는 것이 가장 쉬운 솔루션 중 하나 일 수 있지만 실험적인 API 인 경우 불안정하고 지원되지 않습니다. 다른 모든 것이 실패 할 때만 사용하십시오. 예를 들면 다음과 같습니다.

    import React from "react";
    import PropTypes from "prop-types";
    
    class MyComponent extends React.Component {
      static contextTypes = {
        router: PropTypes.object
      }
      constructor(props, context) {
         super(props, context);
      }
      ...
      myFunction() {
        this.context.router.history.push("/some/Path");
      }
      ...
    }
    

    문맥 에 대한 공식 문서살펴보십시오 .

    응용 프로그램을 안정적으로 유지하려면 컨텍스트를 사용하지 마십시오. 실험적인 API이며 React의 향후 릴리스에서 중단 될 수 있습니다.

    이러한 경고에도 불구하고 컨텍스트 사용을 고집하는 경우 컨텍스트 사용을 작은 영역으로 격리하고 가능한 경우 컨텍스트 API를 직접 사용하지 않도록하여 API가 변경 될 때 쉽게 업그레이드하십시오.


이것이 내가 한 방법입니다.

import React, {Component} from 'react';

export default class Link extends Component {
    constructor(props) {
        super(props);
        this.onLogout = this.onLogout.bind(this);
    }
    onLogout() {
        this.props.history.push('/');
    }
    render() {
        return (
            <div>
                <h1>Your Links</h1>
                <button onClick={this.onLogout}>Logout</button>
            </div>
        );
    }
}

this.props.history.push('/cart');장바구니 페이지로 리디렉션하는 데 사용 하여 내역 개체에 저장됩니다.

즐기세요, 마이클


React Router v4 문서 에 따르면 -Redux Deep Integration 세션

다음을 위해 깊은 통합이 필요합니다.

"조치를 파견하여 탐색 할 수 있습니다"

그러나 이들은 "심층 통합"에 대한 대안으로이 접근 방식을 권장합니다.

"탐색하기 위해 조치를 전달하는 대신 제공된 히스토리 오브젝트를 전달하여 구성 요소를 조치로 라우트하고 거기에서 탐색 할 수 있습니다."

따라서 withRouter 상위 구성 요소로 구성 요소를 랩핑 할 수 있습니다.

export default withRouter(connect(null, { actionCreatorName })(ReactComponent));

히스토리 API를 소품에 전달합니다. 따라서 기록을 매개 변수로 전달하는 액션 제작자를 호출 할 수 있습니다. 예를 들어 ReactComponent 내부에서 :

onClick={() => {
  this.props.actionCreatorName(
    this.props.history,
    otherParams
  );
}}

그런 다음 actions / index.js 내부에서

export function actionCreatorName(history, param) {
  return dispatch => {
    dispatch({
      type: SOME_ACTION,
      payload: param.data
    });
    history.push("/path");
  };
}

React Router 4에서 가장 간단한 방법은

this.props.history.push('/new/url');

그러나이 방법을 사용하려면 기존 구성 요소에 history객체에 대한 액세스 권한이 있어야 합니다. 우리는 액세스 할 수 있습니다

  1. 컴포넌트가 Route직접 링크 된 경우 컴포넌트는 이미 history오브젝트에 액세스 할 수 있습니다.

    예 :

    <Route path="/profile" component={ViewProfile}/>
    

    여기 ViewProfile에 액세스 할 수 history있습니다.

  2. Route직접 연결되지 않은 경우 .

    예 :

    <Route path="/users" render={() => <ViewUsers/>}
    

    그런 다음 withRouter기존 구성 요소를 뒤틀기 위해 heigher order fension 을 사용해야 합니다.

    내부 ViewUsers 구성 요소

    • import { withRouter } from 'react-router-dom';

    • export default withRouter(ViewUsers);

    이제 ViewUsers구성 요소가 history객체에 액세스 할 수 있습니다.

최신 정보

2-이 시나리오에서는 모든 경로 props를 구성 요소로 전달한 다음 구성 요소에서 액세스 할 수 있습니다 this.props.history.HOC

예 :

<Route path="/users" render={props => <ViewUsers {...props} />}

불쾌한 질문, 많은 시간이 걸렸지 만 결국은이 방법으로 해결했습니다.

용기를 포장 withRouter하고 작업 내역을 mapDispatchToProps기능에 전달하십시오 . 실제로 history.push ( '/ url')을 사용하여 탐색하십시오.

동작:

export function saveData(history, data) {
  fetch.post('/save', data)
     .then((response) => {
       ...
       history.push('/url');
     })
};

컨테이너:

import { withRouter } from 'react-router-dom';
...
const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    save: (data) => dispatch(saveData(ownProps.history, data))}
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Container));

이는 React Router v4.x에 유효합니다 .


this.context.history.push 작동 안 할 것이다.

나는 다음과 같이 푸시 작업을 수행했다.

static contextTypes = {
    router: PropTypes.object
}

handleSubmit(e) {
    e.preventDefault();

    if (this.props.auth.success) {
        this.context.router.history.push("/some/Path")
    }

}

이 경우 소품을 썽크에 전달합니다. 그래서 당신은 단순히 전화

props.history.push('/cart')

그렇지 않은 경우 여전히 구성 요소에서 기록을 전달할 수 있습니다

export function addProduct(data, history) {
  return dispatch => {
    axios.post('/url', data).then((response) => {
      dispatch({ type: types.AUTH_USER })
      history.push('/cart')
    })
  }
}

다른 사람에게 가치가있는 경우를 대비하여 하나 이상의 솔루션을 제공합니다.

나는이 history.js내가 다음이 파일을 :

import createHistory from 'history/createBrowserHistory'
const history = createHistory()
history.pushLater = (...args) => setImmediate(() => history.push(...args))
export default history

다음으로 라우터를 정의하는 루트에서 다음을 사용합니다.

import history from '../history'
import { Provider } from 'react-redux'
import { Router, Route, Switch } from 'react-router-dom'

export default class Root extends React.Component {
  render() {
    return (
     <Provider store={store}>
      <Router history={history}>
       <Switch>
        ...
       </Switch>
      </Router>
     </Provider>
    )
   }
  }

마지막으로, actions.js나는 역사를 가져 와서 pushLater를 사용합니다.

import history from './history'
export const login = createAction(
...
history.pushLater({ pathname: PATH_REDIRECT_LOGIN })
...)

이렇게하면 API 호출 후 새로운 작업을 수행 할 수 있습니다.

그것이 도움이되기를 바랍니다!


를 사용하여이 작업을 수행 할 수있었습니다 bind(). 의 버튼을 클릭하고 index.jsx일부 데이터를 서버에 게시하고 응답을 평가하고로 리디렉션하고 싶었 습니다 success.jsx. 내가 그 일을 어떻게했는지 ...

index.jsx:

import React, { Component } from "react"
import { postData } from "../../scripts/request"

class Main extends Component {
    constructor(props) {
        super(props)
        this.handleClick = this.handleClick.bind(this)
        this.postData = postData.bind(this)
    }

    handleClick() {
        const data = {
            "first_name": "Test",
            "last_name": "Guy",
            "email": "test@test.com"
        }

        this.postData("person", data)
    }

    render() {
        return (
            <div className="Main">
                <button onClick={this.handleClick}>Test Post</button>
            </div>
        )
    }
}

export default Main

request.js:

import { post } from "./fetch"

export const postData = function(url, data) {
    // post is a fetch() in another script...
    post(url, data)
        .then((result) => {
            if (result.status === "ok") {
                this.props.history.push("/success")
            }
        })
}

success.jsx:

import React from "react"

const Success = () => {
    return (
        <div className="Success">
            Hey cool, got it.
        </div>
    )
}

export default Success

그래서 바인딩에 의해 thispostDataindex.jsx, 나는 액세스 할 수 있었다 this.props.history에서 request.js바로 확인 내가 포함하는 기억하게해야 ... 그때 다른 구성 요소에서이 기능을 다시 사용할 수 있습니다 this.postData = postData.bind(this)constructor().


콜백을 사용하십시오. 그것은 나를 위해 일했다!

export function addProduct(props, callback) {
  return dispatch =>
    axios.post(`${ROOT_URL}/cart`, props, config)
    .then(response => {
    dispatch({ type: types.AUTH_USER });
    localStorage.setItem('token', response.data.token);
    callback();
  });
}

컴포넌트에서 콜백을 추가하기 만하면됩니다.

this.props.addProduct(props, () => this.props.history.push('/cart'))

여기 내 해킹이 있습니다 (이것은 루트 디렉토리 파일이며 약간의 redux가 혼합되어 있습니다 react-router-redux.

const store = configureStore()
const customHistory = createBrowserHistory({
  basename: config.urlBasename || ''
})

ReactDOM.render(
  <Provider store={store}>
    <Router history={customHistory}>
      <Route component={({history}) => {
        window.appHistory = history
        return (
          <App />
        )
      }}/>
    </Router>
  </Provider>,
  document.getElementById('root')
)

그런 다음 window.appHistory.push()원하는 어디에서나 사용할 수 있습니다 (예 : redux store 함수 / thunks / sagas 등) 방금 사용할 수 있기를 희망 했지만 URL이 변경되었지만 window.customHistory.push()어떤 이유로 든 react-router업데이트되지 않는 것 같습니다. 그러나이 방법으로 EXACT 인스턴스가 react-router사용합니다. 나는 세계적인 범위에 물건을 넣는 것을 좋아하지 않으며, 이것이 내가 할 수있는 몇 가지 중 하나입니다. 그러나 IMO를 본 다른 대안보다 낫습니다.


Redux를 사용하는 경우 npm package react-router-redux를 사용하는 것이 좋습니다 . Redux 상점 탐색 조치를 전달할 수 있습니다.

Readme 파일에 설명 된대로 상점을 작성해야 합니다 .

가장 쉬운 사용 사례 :

import { push } from 'react-router-redux'

this.props.dispatch(push('/second page'));

컨테이너 / 컴포넌트의 두 번째 사용 사례 :

컨테이너:

import { connect } from 'react-redux';
import { push } from 'react-router-redux';

import Form from '../components/Form';

const mapDispatchToProps = dispatch => ({
  changeUrl: url => dispatch(push(url)),
});

export default connect(null, mapDispatchToProps)(Form);

구성 요소:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class Form extends Component {
  handleClick = () => {
    this.props.changeUrl('/secondPage');
  };

  render() {
    return (
      <div>
        <button onClick={this.handleClick}/>
      </div>Readme file
    );
  }
}

React router V4는 이제 히스토리 소품을 아래와 같이 사용할 수있게합니다 :

this.props.history.push("/dummy",value)

그런 다음 위치 소품이 state:{value}구성 요소 상태가 아닌 사용 가능한 모든 위치에 값에 액세스 할 수 있습니다 .


내가 로그인하고 다른 일을 할 때처럼 이렇게 사용할 수 있습니다.

class Login extends Component {
  constructor(props){
    super(props);
    this.login=this.login.bind(this)
  }


  login(){
this.props.history.push('/dashboard');
  }


render() {

    return (

   <div>
    <button onClick={this.login}>login</login>
    </div>

)

/*Step 1*/
myFunction(){  this.props.history.push("/home"); }
/**/
 <button onClick={()=>this.myFunction()} className={'btn btn-primary'}>Go 
 Home</button>

1 단계는 라우터에서 앱을 포장

import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(<Router><App /></Router>, document.getElementById('root'));

이제 내 전체 앱이 BrowserRouter에 액세스 할 수 있습니다. 2 단계 루트를 가져온 다음 해당 소품을 전달합니다. 아마도 기본 파일 중 하나에있을 것입니다.

import { Route } from "react-router-dom";

//lots of code here

//somewhere in my render function

    <Route
      exact
      path="/" //put what your file path is here
      render={props => (
      <div>
        <NameOfComponent
          {...props} //this will pass down your match, history, location objects
        />
      </div>
      )}
    />

이제 컴포넌트 js 파일에서 console.log (this.props)를 실행하면 다음과 같은 것을 얻을 수 있습니다

{match: {…}, location: {…}, history: {…}, //other stuff }

2 단계 기록 개체에 액세스하여 위치를 변경할 수 있습니다

//lots of code here relating to my whatever request I just ran delete, put so on

this.props.history.push("/") // then put in whatever url you want to go to

또한 저는 코딩 부트 캠프 학생 일 뿐이므로 전문가는 아니지만 사용할 수 있다는 것도 알고 있습니다

window.location = "/" //wherever you want to go

내가 틀렸다면 정정하십시오. 그러나 그것을 테스트 할 때 React를 사용하는 전체 요점을 물리 쳤다고 생각한 전체 페이지를 다시로드했습니다.


그래서 그것을 할 방법은 다음과 같습니다 - 사용하는 대신 리디렉션의 history.push, 난 그냥 사용 Redirect에서 구성 요소를 react-router-dom그냥 통과 할 수이 구성 요소를 사용하는 경우 push=true, 그것은 알아서합니다

import * as React from 'react';
import { Redirect } from 'react-router-dom';
class Example extends React.Component {
  componentDidMount() {
    this.setState({
      redirectTo: '/test/path'
    });
  }

  render() {
    const { redirectTo } = this.state;

    return <Redirect to={{pathname: redirectTo}} push={true}/>
  }
}

Router자체적 으로 사용자 정의 작성하십시오 browserHistory.

import React from 'react';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';

export const history = createBrowserHistory();

const ExtBrowserRouter = ({children}) => (
  <Router history={history} >
  { children }
  </Router>
);

export default ExtBrowserRouter

다음으로를 정의한 루트에서 Router다음을 사용하십시오.

import React from 'react';       
import { /*BrowserRouter,*/ Route, Switch, Redirect } from 'react-router-dom';

//Use 'ExtBrowserRouter' instead of 'BrowserRouter'
import ExtBrowserRouter from './ExtBrowserRouter'; 
...

export default class Root extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <ExtBrowserRouter>
          <Switch>
            ...
            <Route path="/login" component={Login}  />
            ...
          </Switch>
        </ExtBrowserRouter>
      </Provider>
    )
  }
}

마지막으로 history필요한 곳을 가져 와서 사용하십시오.

import { history } from '../routers/ExtBrowserRouter';
...

export function logout(){
  clearTokens();      
  history.push('/login'); //WORKS AS EXPECTED!
  return Promise.reject('Refresh token has expired');
}

참고 URL : https://stackoverflow.com/questions/42701129/how-to-push-to-history-in-react-router-v4

반응형