简体   繁体   中英

How to dispatch outside of class component in reactjs / redux?

I'm struggling to understand a concept here i think related to scope and can't put my finger on how to do this.

I'm working on a class component involving redux and antd's table functionality. The table displays fine so that's good. It's pulling in the data from my store and displaying it properly. Here is what it looks like. Note in particular the "Archive" action button at the right which relates to my question.

我的桌子

I decided to use antd's popconfirm tag such that if someone clicks the archive link, they get an additional confirmation dialog. That also works fine. The dialog pops up and i can click yes/no and the corresponding function gets called. My problem is now getting the property to actually update in my redux store. What i'd like it to do is to update the particular property's "archive" (to true) and "archivedate" (to current date) fields in redux if someone proceeds to confirm the popup dialog.

The function in particular where this should happen (ignore the comments. i was trying to update the object):

function confirm(record, e) {
  message.success('Archived');
  // const archived = true;
  console.log("confirm function.. record")
  // setState(() => ({ archived }));
  // record.archived = false;
  // record.archiveddate = moment();
  console.log(record);
}

Through console.log i can see that within my confirm function, I do indeed have access to the particular property (or "record" above) object (eg property.id, property.archived, property.archiveddate). I figure that's important to dispatch the right property id. But i'm not sure what to put inside the confirm function to get this done. In part i think this is because the function is not within the class component and therefore i can't simply do a props.archiveProperty like i otherwise would be able to thanks to the mapdistpatchtoprops.

So in summary, something about antd's table method of making me define this data structure for columns and rows (and functions) outside the class component is messing with my (lack of?) understanding on how scope works here and how to ultimately update my property.

appreciate any guidance!

The entire js file:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import selectProperties from '../selectors/properties';
import { startEditProperty } from '../actions/properties';
import { Table, Tag, Divider, Popconfirm, message } from 'antd';
import moment from 'moment';

const columns = [
  {
    title: 'Address',
    dataIndex: 'street',
    key: 'street',
    render: text => <a>{text}</a>,
  },
  {
    title: 'City',
    dataIndex: 'city',
    key: 'city',
  },
  {
    title: 'State',
    dataIndex: 'state',
    key: 'state',
  },
  {
    title: 'Workflow',
    key: 'workflow',
    dataIndex: 'workflow',
    sorter: (a, b) => a.workflow.length - b.workflow.length,
    sortDirections: ['descend'],
    render: workflow => {
      let color = 'geekblue';
      if (workflow === 'Inspection' || workflow === 'Maintenance' || workflow === 'Cleaning') {
        color = 'volcano';
      }
      else if (workflow === 'Rented') {
        color = 'green';
      }
      return (
        <span>
          <Tag color={color} key={workflow}>
             {workflow.toUpperCase()}
          </Tag>
        </span>
      );
    },
  },
  {
    title: 'Action',
    key: 'action',
    render: (text, record) => (
      <span>
        <a>Edit</a>
        <Divider type="vertical" />
        <Popconfirm
          title="Are you sure?"
          onConfirm={confirm.bind(this, record)}
          onCancel={cancel}
          okText="Yes"
          cancelText="No"
        >
          <a href="#">Archive</a>
        </Popconfirm>
      </span>
    ),
  },
];

function confirm(record, e) {
  message.success('Archived');
  // const archived = true;
  console.log("confirm function.. record")
  // setState(() => ({ archived }));
  // record.archived = false;
  // record.archiveddate = moment();
  console.log(record);
}

function cancel(e) {
  console.log(e);
  message.error('Cancelled');
}

export class PropertyList extends React.Component {
  // onSubmit = (property) => {
  //   this.props.archiveProperty(this.props.property.id, property);
  //   this.props.history.push('/');
  // };
  render() {
    return (
        <div className="content-container">
            <div className="list-body">
            {
                this.props.properties.length === 0 ? (
                <div className="list-item list-item--message">
                    <span>No properties. Add some!</span>
                </div>

                ) : (
                <Table rowKey="id" dataSource={this.props.properties} columns={columns} pagination = { false } footer={() => ''} />
                )
            }
            </div>
        </div>
    )
  }
};

const mapStateToProps = (state) => {
  console.log("PropertyList mapStateToProps..");
  console.log(state);
  return {
    properties: selectProperties(state.properties, state.filters)
  };
};

const mapDispatchToProps = (dispatch) => ({
  archiveProperty: (id, property) => dispatch(startEditProperty(id, property))
});

export default connect(mapStateToProps, mapDispatchToProps)(PropertyList);

First your dispatch will be like this:

const mapDispatchToProps = (dispatch) => ({
  archiveProperty: (id, property) => dispatch('your_type',{id, property})
});

Considering that you are getting the record that you want to update to archive and i am hoping that will have id property. So, in confirm method you have to dispatch the event that you have already defined like this:

function confirm(record, e) {
    message.success('Archived');
    console.log(record);
    this.props.archiveProperty(record.id,record);
}

And your flag changing logic will be in reducer like this:

  [your_type]:(state,action)=>{
      // in action you will get your data that you have passed from dispatch event
      //your logic goes here
      //after your logic,return updated state
  }

See you updated js file:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import selectProperties from '../selectors/properties';
import { startEditProperty } from '../actions/properties';
import { Table, Tag, Divider, Popconfirm, message } from 'antd';
import moment from 'moment';

const columns = [
  {
    title: 'Address',
    dataIndex: 'street',
    key: 'street',
    render: text => <a>{text}</a>,
  },
  {
    title: 'City',
    dataIndex: 'city',
    key: 'city',
  },
  {
    title: 'State',
    dataIndex: 'state',
    key: 'state',
  },
  {
    title: 'Workflow',
    key: 'workflow',
    dataIndex: 'workflow',
    sorter: (a, b) => a.workflow.length - b.workflow.length,
    sortDirections: ['descend'],
    render: workflow => {
      let color = 'geekblue';
      if (workflow === 'Inspection' || workflow === 'Maintenance' || workflow === 'Cleaning') {
        color = 'volcano';
      }
      else if (workflow === 'Rented') {
        color = 'green';
      }
      return (
        <span>
          <Tag color={color} key={workflow}>
             {workflow.toUpperCase()}
          </Tag>
        </span>
      );
    },
  },
  {
    title: 'Action',
    key: 'action',
    render: (text, record) => (
      <span>
        <a>Edit</a>
        <Divider type="vertical" />
        <Popconfirm
          title="Are you sure?"
          onConfirm={confirm.bind(this, record)}
          onCancel={cancel}
          okText="Yes"
          cancelText="No"
        >
          <a href="#">Archive</a>
        </Popconfirm>
      </span>
    ),
  },
];



export class PropertyList extends React.Component {
  // onSubmit = (property) => {
  //   this.props.archiveProperty(this.props.property.id, property);
  //   this.props.history.push('/');
  // };
  confirm = (record, e) => {
    message.success('Archived');
    console.log("confirm function.. record");
    console.log('make sure you are getting recird with all details:',record);
    this.props.archiveProperty(record.id,record);
  }

  cancel = (e) => {
    console.log(e);
    message.error('Cancelled');
  }
  render() {
    return (
        <div className="content-container">
            <div className="list-body">
            {
                this.props.properties.length === 0 ? (
                <div className="list-item list-item--message">
                    <span>No properties. Add some!</span>
                </div>

                ) : (
                <Table rowKey="id" dataSource={this.props.properties} columns={columns} pagination = { false } footer={() => ''} />
                )
            }
            </div>
        </div>
    )
  }
};

const mapStateToProps = (state) => {
  console.log("PropertyList mapStateToProps..");
  console.log(state);
  return {
    properties: selectProperties(state.properties, state.filters)
  };
};

const mapDispatchToProps = (dispatch) => ({
  archiveProperty: (id, property) => dispatch('your_type',{id, property})
});

export default connect(mapStateToProps, mapDispatchToProps)(PropertyList);

I moved your confirm function in component. Let me know if this worked.

Easiest and best way to achieve it.

import store from 'your_store_path_here';

store.dispatch(someAction)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM