React Hooks with React Router v4 - how do I redirect to another route?

大兔子大兔子 提交于 2019-12-04 21:01:47

问题


I have a simple react hooks application - a list of Todos - with react router v4

On the List of Todos, when a Todo is clicked I need to:

  1. Dispatch the current todo in context
  2. Redirect to another route (from /todos to /todos/:id)

In the previous React Class based implementation I could use this.context.history.push to redirect to another route.

How would I handle that using React Hooks in combination of React Router v4 (in code below see my comment in function editRow())?

Code below:

=====index.js=====

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter} from "react-router-dom"

import App from './App';

ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>, document.getElementById('root'));

=====main.js=====

import React from 'react'
import { Switch, Route } from 'react-router-dom'
import TodosList from './todoslist'
import TodosEdit from './todosedit'

const Main = () => (
  <main>
    <Switch>
      <Route exact path="/todos" component={TodosList}/>
      <Route exact path="/todos/:id" component={TodosEdit} />
    </Switch>
  </main>
)

export default Main

=====app.js=====

import React, {useContext, useReducer} from 'react';
import Main from './main'
import TodosContext from './context'
import todosReducer from './reducer'

const App = () => {
  const initialState = useContext(TodosContext);
  const [state, dispatch] = useReducer(todosReducer, initialState);
  return (
    <div>
      <TodosContext.Provider value={{state, dispatch}}>
        <Main/>
      </TodosContext.Provider>
    </div>
  )
}
export default App;

=====TodosContext.js=====

import React from 'react'

const TodosContext = React.createContext({
    todos: [
        {id:1, text:'Get Grocery', complete:false},
        {id:2, text:'Excercise', complete:false},
        {id:3, text:'Drink Water', complete:true},
    ],
    currentTodo: {}
})

export default TodosContext

=====reducer.js=====

import React from 'react'

export default function reducer(state, action){
    switch(action.type){
        case "GET_TODOS":
            return {
                ...state,
                todos: action.payload
            }
        case "SET_CURRENT_TODO":
                   return {
                       ...state,
                       currentTodo: action.payload
            }
        default: 
            return state
    }
}

=====Todos.js=====

import React, {useState, useContext, useEffect} from 'react';
import TodosContext from './context'

function Todos(){   
    const [todo, setTodo] = useState("")
    const {state, dispatch} = useContext(TodosContext)
    useEffect(()=>{
        if(state.currentTodo.text){
            setTodo(state.currentTodo.text)
        } else {
            setTodo("")
        }
        dispatch({
            type: "GET_TODOS",
            payload: state.todos
        })
    }, [state.currentTodo.id])

    const editRow = event =>{
        let destUrlEdit = `/todos/${event.id}`

        let obj = {}
        obj.id = event.id
        obj.text = event.text

        dispatch({type:"SET_CURRENT_TODO", payload: obj})

        //after dispatch I would like to redirect to another route to do the actual edit
        //destUrlEdit
    }
    return(
        <div>
            <h1>List of ToDos</h1>
            <h4>{title}</h4>
            <ul>
                {state.todos.map(todo => (
                    <li key={todo.id}>{todo.text} &nbsp;
                        <button onClick={()=>{
                            editRow(todo)}}>
                        </button>
                    </li>
                ))}
            </ul>
        </div>
    )
}

export default Todos;

回答1:


Your problem is related to Programmatically navigating using react-router-v4 instead of with hooks,

In react-router-v4, you would get history from props if the Todos component is rendered as a child or Route or from an ancestor that is render form Route and it passed the Router props to it. However it is not receiving Router props, you can use withRouter HOC from react-router to get the router props and call props.history.push(destUrlEdit)

import React, {useState, useContext, useEffect} from 'react';
import TodosContext from './context'
import { withRouter } from 'react-router-dom';

function Todos(props){   
    const [todo, setTodo] = useState("")
    const {state, dispatch} = useContext(TodosContext)
    useEffect(()=>{
        if(state.currentTodo.text){
            setTodo(state.currentTodo.text)
        } else {
            setTodo("")
        }
        dispatch({
            type: "GET_TODOS",
            payload: state.todos
        })
    }, [state.currentTodo.id])

    const editRow = event =>{
        let destUrlEdit = `/todos/${event.id}`

        let obj = {}
        obj.id = event.id
        obj.text = event.text

        dispatch({type:"SET_CURRENT_TODO", payload: obj})

        //after dispatch I would like to redirect to another route to do the actual edit
        //destUrlEdit
        props.history.push(destUrlEdit);
    }
    return(
        <div>
            <h1>List of ToDos</h1>
            <h4>{title}</h4>
            <ul>
                {state.todos.map(todo => (
                    <li key={todo.id}>{todo.text} &nbsp;
                        <button onClick={()=>{
                            editRow(todo)}}>
                        </button>
                    </li>
                ))}
            </ul>
        </div>
    )
}

export default withRouter(Todos);



回答2:


Using react-redux and connected-react-router...

import {useDispatch } from 'react-redux';
import { push } from 'connected-react-router';

export default () => {
 const dispatch = useDispatch();

 return (
   <Button onClick={() => dispatch(push('/login'))}>
     Login
   </Button>    
  );
};


来源:https://stackoverflow.com/questions/54579730/react-hooks-with-react-router-v4-how-do-i-redirect-to-another-route

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!