React Hooks with React Router v4 - 如何重定向到另一条路由? [英] React Hooks with React Router v4 - how do I redirect to another route?

查看:64
本文介绍了React Hooks with React Router v4 - 如何重定向到另一条路由?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 react hooks 应用程序 - 一个 Todos 列表 - 带有 react router v4

在待办事项列表中,当点击待办事项时,我需要:

  1. 在上下文中调度当前待办事项
  2. 重定向到另一个路由(从/todos 到/todos/:id)

在之前基于 React 类的实现中,我可以使用 this.context.history.push 重定向到另一个路由.

我将如何将 React Hooks 与 React Router v4 结合使用来处理这个问题(在下面的代码中,请参阅我在函数 editRow() 中的注释)?

代码如下:

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

从'react'导入React;从 'react-dom' 导入 ReactDOM;从react-router-dom"导入 { BrowserRouter}从'./App'导入应用程序;ReactDOM.render(<浏览器路由器><应用程序/></BrowserRouter>, document.getElementById('root'));

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

从 'react' 导入 React从'react-router-dom'导入{开关,路由}从 './todoslist' 导入 TodosList从 './todosedit' 导入 TodosEditconst Main = () =>(<主要><开关><路由精确路径="/todos" component={TodosList}/><路由精确路径="/todos/:id" component={TodosEdit}/></开关></main>)导出默认主

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

import React, {useContext, useReducer} from 'react';从 './main' 导入 Main从 './context' 导入 TodosContext从 './reducer' 导入 todosReducerconst App = () =>{const initialState = useContext(TodosContext);const [state, dispatch] = useReducer(todosReducer, initialState);返回 (<div><TodosContext.Provider value={{state, dispatch}}><主要/></TodosContext.Provider>

)}导出默认应用程序;

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

从 'react' 导入 Reactconst TodosContext = React.createContext({待办事项: [{id:1, text:'Get Grocery', complete:false},{id:2, text:'Excercise', complete:false},{id:3, text:'Drink Water', complete:true},],当前待办事项:{}})导出默认的 TodosContext

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

从 'react' 导入 React导出默认函数reducer(状态,动作){开关(动作.类型){案例GET_TODOS":返回 {...状态,待办事项:action.payload}案例SET_CURRENT_TODO":返回 {...状态,currentTodo: action.payload}默认:返回状态}}

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

import React, {useState, useContext, useEffect} from 'react';从 './context' 导入 TodosContext函数 Todos(){const [todo, setTodo] = useState("")const {state, dispatch} = useContext(TodosContext)useEffect(()=>{如果(state.currentTodo.text){setTodo(state.currentTodo.text)} 别的 {setTodo("")}派遣({类型:GET_TODOS",有效载荷:state.todos})}, [state.currentTodo.id])const editRow = 事件 =>{让 destUrlEdit = `/todos/${event.id}`让 obj = {}obj.id = 事件.idobj.text = 事件.文本调度({类型:SET_CURRENT_TODO",有效载荷:obj})//调度后我想重定向到另一条路线进行实际编辑//destUrlEdit}返回(<div><h1>待办事项列表</h1><h4>{title}</h4><ul>{state.todos.map(todo => (<li key={todo.id}>{todo.text} &nbsp;<button onClick={()=>{editRow(todo)}}>))}

)}导出默认的 Todos;

解决方案

您的问题与使用 react-router-v4 而不是使用钩子进行编程导航有关,

在 react-router-v4 中,如果 Todos 组件被渲染为子组件或路由,或者来自渲染表单 Route 的祖先,并且它将路由器道具传递给它,您将从道具中获取历史记录.但是它没有接收路由器道具,您可以使用 react-router 中的 withRouter HOC 来获取路由器道具并调用 props.history.push(destUrlEdit)

import React, {useState, useContext, useEffect} from 'react';从 './context' 导入 TodosContext从'react-router-dom'导入{ withRouter };功能 Todos(props){const [todo, setTodo] = useState("")const {state, dispatch} = useContext(TodosContext)useEffect(()=>{如果(state.currentTodo.text){setTodo(state.currentTodo.text)} 别的 {setTodo("")}派遣({类型:GET_TODOS",有效载荷:state.todos})}, [state.currentTodo.id])const editRow = 事件 =>{让 destUrlEdit = `/todos/${event.id}`让 obj = {}obj.id = 事件.idobj.text = 事件.文本调度({类型:SET_CURRENT_TODO",有效载荷:obj})//调度后我想重定向到另一条路线进行实际编辑//destUrlEditprops.history.push(destUrlEdit);}返回(<div><h1>待办事项列表</h1><h4>{title}</h4><ul>{state.todos.map(todo => (<li key={todo.id}>{todo.text} &nbsp;<button onClick={()=>{editRow(todo)}}>))}

)}导出默认 withRouter(Todos);

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;

解决方案

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);

这篇关于React Hooks with React Router v4 - 如何重定向到另一条路由?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆