Изменение URL в React / Redux - PullRequest
0 голосов
/ 17 мая 2018

Я пытаюсь создать приложение с React и Redux (DVA).Он использует Ant.Design в качестве основного фреймворка.Я пытаюсь изменить URL-адрес, когда пользователь нажимает кнопку, и, очевидно, «привязать» это изменение URL к действию, чтобы, если пользователь переходит непосредственно к этому URL-адресу, он получал то, что хотел.

На данный момент вот что у меня есть, в функции в моем компоненте.

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

Это единственное, что я смог произвести.Он корректно изменяет URL, но не связывает URL с определенным поведением, что делает его совершенно бесполезным.

Как мне связать URL с действием?

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Я не могу разместить код на 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 (ответственныйдля отображения списка ссылок, по которым пользователь будет щелкать по одной из них, что будет делать 2 вещи:
- соответственно изменить URL-адрес
- отобразить конкретные данные на 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-адреса или нажатие левой панели и отображение данных соответствующим образом.

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 вызывает метод selectRow в users.js, который, в свою очередь, выбирает строкуи отобразить его на RightPanel.js.

Мой вопрос: как добавить к этому тот факт, что он меняет URL-адрес всякий раз, когда пользователь нажимает?И очевидно, что если пользователь нажимает кнопку «вернуться» в Chrome, данные в RightPanel.js должны соответственно измениться ..?

0 голосов
/ 17 мая 2018

Если вы хотите запустить действие на основе URL-адреса, вам нужно будет использовать react-router для маршрутизации компонента, который затем выполняет желаемое действие.В таком случае также полезно посетить другой URL-адрес, удалив URL-адрес действия из истории браузера.

Типичное определение маршрутизатора может выглядеть примерно так (взято из реаги-документы router-redux ):

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.Это означает, что когда пользователь посещает этот URL, его действие будет выполнено, и он в конечном итоге будет /success.Но если они нажмут кнопку «Назад», они не будут повторно посещать этот URL и снова запускать действие.

...