更改React / Redux中的URL

时间:2018-05-17 19:03:34

标签: javascript reactjs redux react-router antd

我正在尝试使用React和Redux(DVA)构建应用程序。它使用Ant.Design作为主要框架。我试图在用户点击按钮时更改URL,并且显然“绑定”该URL更改为某个操作,这样如果用户直接访问该URL,他就会得到他想要的内容。

目前这就是我所拥有的,在我的组件中的一个函数中。

const { dispatch, match } = this.props;
dispatch(routerRedux.push('/f/' + record.id));

这是我唯一能够制作的东西。它正确地更改了URL,但没有将url与特定行为绑定,使其完全无用。

如何链接带有操作的网址?

2 个答案:

答案 0 :(得分:2)

如果您希望基于URL触发操作,则需要使用react-router来路由然后执行所需操作的组件。在这种情况下,最好还是访问其他网址,从浏览器的历史记录中删除操作网址。

典型的路由器定义可能如下所示(取自react-router-redux's docs):

ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <div>
        <Route exact path="/" component={Home}/>
        <Route path="/about" component={About}/>
        <Route path="/success" component={Success}/>
      </div>
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root')
)

因此,您希望添加路径/f/<record-id>。您可以通过添加如下行来执行此操作:

<Route path="/f/:recordId" component={MyActionComponent}/>

现在您需要定义一个将执行操作的组件MyActionComponent

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

const mapDispatchToProps = (dispatch: Dispatch) => ({
  visitNextLocation: () => dispatch(replace('/success')),
  myAction: (recordId) => dispatch(myAction(recordId)),
});

const withDispatch = connect(null, mapDispatchToProps);

class MyActionComponent extends Component {
  props: {
    match: {
      params: {
        recordId: string,
      }
    },
    redirectToLogin: () => void,
    myAction: string => void,
  };

  componentWillMount() {
    const recordId = this.props.match.params.recordId;
    if (recordId) {
      this.props.myAction(token);
      this.props.visitNextLocation();
    }
  }

  render() {
    return null;
  }
}

请注意使用replace代替push。这意味着,当用户访问此网址时,他们的操作将会执行,并且他们将以/success结束。但是,如果他们点击“返回”按钮,他们就不会重新访问此网址并再次执行操作。

答案 1 :(得分:0)

出于隐私原因,我无法将代码放在Codepen上。但这是一个摘录:

router.js

...
},
'/users': {
  component: dynamicWrapper(app, ['rule'], () => import('../routes/users')),
},
'/f/:userID': {
  component: dynamicWrapper(app, ['rule'], () => import('../routes/users')),
},
...

users.js(包含LeftPanel和RightPanel的主要组件)

import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { Row, Col, Card, List, Divider, Badge, Select, Radio, Input, Popover, Button, Table, Spin } from 'antd';
import RightPanel from './RightPanel';
import LeftPanel from './LeftPanel';
import { routerRedux, Route, Switch } from 'dva/router';
import 'font-awesome/css/font-awesome.min.css';
import FadeIn from 'react-fade-in';

@connect(({ rule, loading }) => ({rule, loading: loading.models.rule }))
export default class Users extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          selected_user: [],
          defaultView: true,
          isLoadingNow: false,
          selectedRowKeys: [],
          makeEmpty: false,
          searchRes: []
      }
    }

        selectRow = (record) => {       
            const { dispatch, match } = this.props;
            dispatch(routerRedux.replace({ pathname: '/f/' + record.id }));

            this.setState({isLoadingNow: true, selectedRowKeys: record.key})
            setTimeout(() => {
              this.setState({
                    isLoadingNow: false,
                    defaultView: false,
                    selected_user: record
                })
            }, 75)
        }

        componentDidMount() { 
            const { dispatch, match } = this.props;
            dispatch({
                type: 'rule/fetch'
            });
            if (match.params.userID == undefined) {
                // do nothing
            } else if (match.params.userID) {
                var result = this.props.rule.data.list.filter(function( obj ) {
                  return obj.id == match.params.userID;
                });
                this.selectRow.bind(this, result[0])
            }
        }

        render() {

            const { selectedRowKeys } = this.state;
            const rowSelection = {
                selectedRowKeys,
                type:"radio"
            };

            const { rule: { data }, loading } = this.props;

            return (<div>

                            <LeftPanel
                                rowSelection={rowSelection}
                                dataSource={this.state.makeEmpty ? this.state.searchRes : this.props.rule.data.list} 
                                selectRow={this.selectRow} 
                                loadingStatus={loading}
                            />
                          <RightPanel 
                                selected_user={this.state.selected_user}
                                is_default={this.state.defaultView}
                                loading={this.state.isLoadingNow}
                          />
                        </div>);


}
}

leftPanel.js(负责显示链接列表,用户将在其上单击一个,这将做两件事:
- 相应更改网址
- 在RightPanel.js上显示特定数据)

import React from 'react';
import { Table, Card } from 'antd';

import styles from './index.less';
// import 'font-awesome/css/font-awesome.min.css';

import { Row, Col, List, Divider, Badge, Select, Radio, Input, Popover, Button } from 'antd';

var moment = require('moment');

class LeftPanel extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            selected_row_index: undefined
        }
    }   
    handleChangeStyleOnSelectRow(index) {
        this.setState({
            selected_row_index: index
        }, console.log(this.state.selected_row_index))
    }

    prettifyForTable(raw_data) {
      var prettyRows = [];
      raw_data.map((item,index) =>
        prettyRows.push(
          <div style={{"width": "100%"}}> 
            <Row style={{  "align-items": "center"}} type="flex" justify="space-between">
                <Col span={10}>
                    <div style={{"font-size": "15px", "text-align": "center"}}>
                        {item.user_name} <i style={{"color": "rgba(0, 0, 0, 0.25)", "margin": "0 10px", "transform": "rotate(45deg)"}} className="fa fa-plane"> </i> {item.user_age}
                        <div style={{"font-size": "12px", "color": "grey"}}> {moment(item.user_color).format('HH:MM')} · {moment(item.user_order).format('HH:MM')}  </div>
                    </div>
                </Col>
                <Col span={3}>
                    <div style={{"text-align": "right", "text-align": "center"}}>
                      {item.user_family}
                    </div>
                </Col>
                <Col span={6}>
                    <div style={{"text-align": "right", "text-align": "center"}}>
                      {moment(item.user_height).format('MMMM D')}
                    </div>
                </Col>
                <Col span={3}>
                    <div style={{"text-align": "center"}}>
                        {(item.status == "in_progress") ? <div> <Badge style={{"padding-right": "25px"}} status="processing"/></div> : <div style={{"text-align": "center"}}> <Badge style={{"padding-right": "25px"}} status="default"/></div>}
                    </div>
                </Col>
            </Row>
          </div>
        )
      );
      return prettyRows;
    }


  render() {
    const stylesSelectedRow = { "background": "rgba(155,155,155,0.05)", "box-shadow": "0 0 5px 0 #4A90E2", "transform": "scale(1.01)"};
    const { dataSource } = this.props;
        return(
         <div>
            {dataSource &&
          <Card bordered={false} loading={this.props.loadingStatus} className={styles.userRows} bodyStyle={{"padding": "0 15px"}}>
                <List
                  size="small"
                  bordered={false}
                  dataSource={this.prettifyForTable(dataSource)}
                  renderItem={(item, index) => (<List.Item onClick={() => {this.state.selected_row_index == index ? null : this.props.selectRow(this.props.dataSource[index]); this.handleChangeStyleOnSelectRow(index)}} style={this.state.selected_row_index == index ? stylesSelectedRow : null} className={styles.userRows}>{item}</List.Item>)}
                />
          </Card>
            }
        </div>
    )
  }
}

export default LeftPanel;

最后是RightPanel.js,用于侦听URL或点击LeftPanel,并相应地显示数据。

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import infopng from '../../../assets/info.svg';

import TabInformations from './TabInformations.js';
import TabFamily from './TabFamily.js';
import TabProblems from './TabProblems.js';
import { Tabs, Button, Spin, Icon, Table, Pagination, Card, Col, Row, Spinner, Badge } from 'antd';
const TabPane = Tabs.TabPane;
import 'font-awesome/css/font-awesome.min.css';
import WindowSizeListener from 'react-window-size-listener'
import FadeIn from 'react-fade-in';

export default class RightPanel extends Component {

  render() {

    if (this.props.loading) {
        return(
            <div> 
          <Spin 
            indicator={<Icon type="loading" style={{ fontSize: 24 }} spin />}
                    src="http://web.gndu.ac.in/DepartmentProfile/images/spinner.gif"
                />
            </div>
        );
    } else if (this.props.is_default) {
      return(
          <div style={{"margin-top": "64px", "margin-right": "10px", "text-align": "center", "height": "90vh", "display": "flex", "align-items": "center", "justify-content": "center"}}> 
            <div>
                <img src={infopng} style={{"height": "155px"}} />
                <p style={{"color": "#8e8e8e"}}> select a user on the <br/> left-hand side... </p>
               </div>
          </div>
        );
    } else {
    return (

      <FadeIn>

      <Card bodyStyle={{"padding": "0"}} style={{"background-color": "white", "height":"90vh", "padding": "20px", "box-shadow": "rgba(0, 21, 41, 0.1) 0px 0px 6px", "opacity": "1", "transition": "background 0.6s", "border-radius": "2px", "margin": "10px 10px 0 0px", "margin-top": "64px"}}> 
            <Tabs defaultActiveKey="1" style={{"text-align": "center", "padding": "0 15px"}}>
        <TabPane tab="General" key="1">
          <TabInformations
                    selected_user={this.props.selected_user}
                />
            </TabPane>
            <TabPane tab="Servicing" key="2">
          <TabFamily 
            selected_user={this.props.selected_user} 
          />
          </TabPane>
          <TabPane tab={<div>Defect(s)<Badge showZero count={0} style={{ backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset', "margin-left": "10px" }} /></div>} key="3">
          <TabProblems />
        </TabPane>
        </Tabs>
    </Card>
    </FadeIn>
    );
  }
}
}

此代码完成初始工作:当用户单击leftPanel.js上的链接时,leftPanel.js调用users.js中的方法selectRow,后者又选择一行并显示在RightPanel.js。

我的问题:如何添加到用户点击时更改网址的事实?显然,如果用户在Chrome中点击“返回”,则RightPanel.js中的数据必须相应更改。?