无状态组件 React 路由器

Posted

技术标签:

【中文标题】无状态组件 React 路由器【英文标题】:Stateless component React router 【发布时间】:2018-11-26 11:33:24 【问题描述】:

我是 React 和 Redux 的新手,我实际上是在创建自己的代码,但我被无状态组件中的路由器之类的东西卡住了。

所以,实际上我需要使用 this.props.history.push('/somepath') 来路由到一个组件。这不会发生在无状态组件内部。

我的无状态组件是

import React from "react"; // eslint-disable-line no-unused-vars
import "bootstrap/dist/css/bootstrap.min.css";
import "./header.css";

const Header = () => (

    handleAuthor() 
        this.props.history('/somepath')// this is not working
    ,

    render()
        return (
            <div className = "header">
                <h1 onClick = this.handleAuthor.bind(this)>this.props.headerText</h1>
            </div>
        );
     
);

export default Header;

我在另一个无状态组件(如 mainlayout)中调用它

import React from "react"; // eslint-disable-line no-unused-vars
import Header from "../header/Header"; // eslint-disable-line no-unused-vars
import Footer from "../footer/Footer"; // eslint-disable-line no-unused-vars
import "./mainLayout.css";

const MainLayout = props => (
    render() 
        return (
            <div className="App">
                <Header headerText = "RK Boilerplate"/>
                <div className = "mainLayout">
                    <main>props.children</main>
                </div>
                <Footer />
            </div>
        );
    
);

export default MainLayout;

我的主文件 index.js 是这样的

import React from "react"; // eslint-disable-line no-unused-vars
import ReactDOM from "react-dom"; // eslint-disable-line no-unused-vars
import  matchRoutes, renderRoutes  from "react-router-config"; // eslint-disable-line no-unused-vars
import  Router  from "react-router-dom"; // eslint-disable-line no-unused-vars
import  Switch  from "react-router"; // eslint-disable-line no-unused-vars
import  Provider  from "react-redux"; // eslint-disable-line no-unused-vars
import store from "./store"; // eslint-disable-line no-unused-vars
import routes from "./routes"; // eslint-disable-line no-unused-vars
import MainLayout from "./components/mainLayout/MainLayout"; // eslint-disable-line no-unused-vars

import createHistory from "history/createBrowserHistory";
let history = createHistory();
const App =  document.getElementById("app");

export default App;

ReactDOM.render(
    <Provider store=store>
        <MainLayout>
            <Router history= history>
                <Switch>
                    renderRoutes(routes)
                </Switch>
            </Router>
        </MainLayout>                 
    </Provider>, 
    App);

所以我需要的是我必须从标头路由到另一个组件,该组件和路径在路由器文件中给出

路由器.js

import Home from "../containers/Home";
import About from "../containers/About";
import CreateUser from "../containers/CreateUser";

import Layout from "../containers/Layout";

const routes = [
     path: "/",
        exact: true,
        component: Layout
    ,
     path: "/home",
        exact: true,
        component: Home
    ,
    
        path:"/About",
        exact: true,
        component: About
    ,
    
        path:"/createUser",
        exact: true,
        component: CreateUser
    
];

export default routes;

当我尝试从标头进行路由时,出现类似 push of undefined 的错误。 我错过了什么吗?我应该在这里做些什么改变。

提前致谢。

【问题讨论】:

您可能已经知道这一点,但您没有将props 传递到您的Header 组件中,这就是您得到未定义错误的原因。您可以这样尝试:const Header = (props) =&gt; ...,然后通过props.history(没有this)访问您的history。您还可以使用解构使其内部看起来更干净。 【参考方案1】:

您可以直接导入历史对象并从中推送。例如尝试下面的代码。

import React from "react"; // eslint-disable-line no-unused-vars
import "bootstrap/dist/css/bootstrap.min.css";
import "./header.css";
import history from "/your/history/path" //try this

const Header = () => (

    handleAuthor() 
        history.push('/somepath')// change to this
    ,

    render()
        return (
            <div className = "header">
                <h1 onClick = this.handleAuthor.bind(this)>this.props.headerText</h1>
            </div>
        );
     
);

export default Header;

像下面这样创建浏览器历史记录,并通过导入在任何地方使用它。

import createBrowserHistory from 'history/createBrowserHistory';

export default createBrowserHistory();

【讨论】:

这行不通,因为它会改变 URL,但组件不会被渲染 我不知道你的意思,但是当我使用它时它工作得很好 我更新了答案。看看这是否适合你。 - 我一直这样做 能否请您粘贴代码让我检查,我不知道我在这里缺少什么 检查这个 repo。 github.com/serendipity1004/MERN-stack-boilerplate 历史文件位于client/services/history.js。正在client/containers/App.js 进行导入。您可以对任何其他组件使用完全相同的导入来移动路由并渲染组件【参考方案2】:

希望这不会来得太晚。我可以成功地从有状态组件重定向,但我想将我的组件转换为无状态组件,因为唯一使它成为有状态的是重定向位。我对反应还很陌生,而且那里的大多数资源都不是很清楚。我就是这样做的。

import React from "react"; // eslint-disable-line no-unused-vars
import "bootstrap/dist/css/bootstrap.min.css";
import "./header.css";

const Header = (props) => 
    return (
        <div className = "header">
            <h1 onClick = props.history.push('/some-path')>props.headerText</h1>
        </div>
    );
 

export default Header;

【讨论】:

【参考方案3】:

使用 withRouter 对我有用,(加上忽略打字稿警告):

import  withRouter  from 'react-router-dom';

...

type Props =  myProp: boolean ;

// @ts-ignore
export const MyComponent: FC<Props> = withRouter(( myProp, history ) => 

...

)

【讨论】:

【参考方案4】:

2019 年,React Router v4 现在为无状态/函数式组件添加了 useHistory 钩子:

https://reacttraining.com/react-router/web/api/Hooks/usehistory

来自文档:

import  useHistory  from "react-router-dom";

function HomeButton() 
  let history = useHistory();

  function handleClick() 
    history.push("/home");
  

  return (
    <button type="button" onClick=handleClick>
      Go home
    </button>
  );

【讨论】:

谢谢,但我收到此错误。尝试导入错误:“useHistory”未从“react-router-dom”导出。我使用 "react": "^16.9.0", "react-router-dom": "^5.0.1", 不幸的是,它仅在 5.1 中添加(reacttraining.com/blog/react-router-v5-1/#usehistory)。 奇怪的是这种方法不起作用。我正在使用 React 路由器 5,我的 React 版本是 16+。地址更改但组件未呈现!

以上是关于无状态组件 React 路由器的主要内容,如果未能解决你的问题,请参考以下文章

React Typescript:添加位置状态以响应路由器组件

react生命周期

如何在 nextjs 的 getInitialProps 无状态组件中访问路由器参数

在组件之间路由时如何保持 React 新的 Context API 状态?

登录页面后反应路由器 v6 不会切换到主页:警告:无法对未安装的组件执行 React 状态更新

路由器事件在构造函数上使用时会导致错误警告:无法对未安装的组件执行 React 状态更新