反应:单击按钮后重新渲染组件

时间:2020-02-05 18:13:01

标签: javascript reactjs axios

单击提交按钮后,如何刷新页面或在页面中呈现内容?我试图将window.location.reload()(我知道不是React的方式,this.forceUpdate()的结果相同)放在提交函数(closeTicket()openTicketSubmit())中,但POST请求不这样做无法得到回应

OpenTickets.js

import React from "react";
import axios from "axios";

import CardConversation from './CardConversation.jsx';

export default class PersonList extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            people: [],
            send_to_number: "",
            message_body: ""
        };

        this.closeTicket = this.closeTicket.bind(this);
        this.openTicketsReply = this.openTicketsReply.bind(this);
        this.openTicketsSubmit = this.openTicketsSubmit.bind(this);
        this.getPhoneNumberOpenTickets = this.getPhoneNumberOpenTickets.bind(this);
    }

    openTicketsReply = async e => {
        this.setState({
            [e.target.name]: e.target.value
        });
    };

    getPhoneNumberOpenTickets = async e => {
        this.setState({
            send_to_number: e
        });
    };

    openTicketsSubmit = async e => {
        e.preventDefault();
        const formData = new FormData();
        formData.set("send_to_number", this.state.send_to_number.slice(1));
        formData.set("message_body", this.state.message_body);
        axios({
            method: "post",
            url: "/outgoingsms",
            data: formData,
            headers: { "Content-Type": "multipart/form-data" }
        })
    };

    closeTicket = async e => {
        e.preventDefault();
        const formData = new FormData();
        formData.set("customernum", this.state.send_to_number.slice(1));
        axios({
            method: "post",
            url: "/closeticket",
            data: formData,
            headers: { "Content-Type": "multipart/form-data" }
        })
    };


    componentDidMount() {
        this.getPeopleData();
    }

    getPeopleData = async () => {
        try {
            const { data } = await axios.get(`/getongoing?limit=10`);
            this.setState({ people: data });
        } catch (e) {
            console.log("error: ", e);
        }
    };

    render() {
        const {
            closeTicket,
            openTicketsSubmit,
            getPhoneNumberOpenTickets,
            openTicketsReply
        } = this;

        return this.state.people.map(person => (
            <CardConversation
                person={person}
                closeTicket={closeTicket}
                openTicketsSubmit={openTicketsSubmit}
                getPhoneNumberOpenTickets={getPhoneNumberOpenTickets}
                openTicketsReply={openTicketsReply}
            />
        ));
    }
}

CardConversation.jsx

import React, { useCallback, useEffect, useState } from "react";
import { Button, Accordion, Card, Form, Row, Col } from "react-bootstrap";
import axios from "axios";

const CardConversation = ({
                              person,
                              closeTicket,
                              openTicketsSubmit,
                              getPhoneNumberOpenTickets,
                              openTicketsReply,
                          }) => {
    const [conversation, setConversation] = useState([]);

    // Handlers
    const handleSubmit = useCallback(
        e => {
            openTicketsSubmit(e);
        },
        [openTicketsSubmit]
    );

    const handleCloseTicket = useCallback(
        e => {
            closeTicket(e);
        },
        [closeTicket],
    );

    const handleClick = useCallback(() => {
        getPhoneNumberOpenTickets(person);
    },
        [person, getPhoneNumberOpenTickets]);

    const handleChange = useCallback(
        e => {
            openTicketsReply(e);
        },
        [openTicketsReply]
    );

    // Methods
    const fetchConversation = useCallback(async () => {
        try {
            const { data } = await axios.get(
                "/getconvfornum?customer_number=" + person.slice(1)
            );
            setConversation(data);
        } catch (e) {
            console.log("error: ", e);
        }
    }, [person, conversation]);

    // Effects
    useEffect(() => {
        fetchConversation(person)
    }, [person]);

    return (
        <Accordion defaultActiveKey="0">
            <Card>
                <Card.Header>
                    <Accordion.Toggle as={Button} variant="button" eventKey="0">
                        Conversation {person.indexOf(person)+1+ '    '}
                        Phone number: {person}
                    </Accordion.Toggle>
                </Card.Header>
                <Accordion.Collapse eventKey="0">
                    <Card.Body>
                        {conversation.map(message => (
                            <div>
                                <p>{message.from}</p>
                                <p>{message.body}</p>
                            </div>
                        ))}
                        <Form onSubmit={handleSubmit}>
                            <br />
                            <Form.Group as={Row} controlId="formPlaintextPassword">
                                <Col sm="10">
                                    <Form.Control
                                        type="text"
                                        placeholder="Reply"
                                        name="message_body"
                                        onChange={handleChange}
                                    />
                                </Col>
                                <Button type={"submit"}
                                        onClick={handleClick} column sm="2">
                                    Reply
                                </Button>
                            </Form.Group>
                        </Form>
                        <Form onSubmit={handleCloseTicket}>
                            <Form.Group>
                                <Col sm="11">
                                    <Button type={"submit"}
                                            onClick={handleClick} column sm="4">
                                        Close Ticket
                                    </Button>
                                </Col>
                            </Form.Group>
                        </Form>
                    </Card.Body>
                </Accordion.Collapse>
            </Card>
            <br />
        </Accordion>
    );
};

export default CardConversation;

7 个答案:

答案 0 :(得分:2)

您可以通过更新其state(在POST之后)来重新渲染组件:

closeTicket = async e => {
  e.preventDefault();
  const formData = new FormData();
  formData.set("customernum", this.state.send_to_number.slice(1));
  axios({
      method: "post",
      url: "/closeticket",
      data: formData,
      headers: { "Content-Type": "multipart/form-data" }
  })
  .then(() => {
    this.setState({ /* */ })
    // or
    // this.forceUpdate();
  })
};

答案 1 :(得分:2)

一种简单的重新渲染方法是在提交Axios请求时更改状态变量,从而导致组件自动重新渲染。 示例:

axios({...}).then(resp => {
 this.setState({message_body:'',send_to_number:''}); // will cause to re-render
})

答案 2 :(得分:1)

状态更改后,React将重新渲染组件,这意味着您只需单击提交按钮即可更改状态。由于提交按钮位于PersonList组件内部,并且您还想重新加载PersonList,因此您想在单击Submit按钮时更改PersonList的状态。

这是您可能想要做的: 1)向PersonList添加“重新加载”状态,默认为false。这将告诉组件是否需要重新加载。 2)传递一个将PersonList的重载值状态设置为子组件的函数,在本例中为CardConversion。像this.setState({reload:!this.state.reload})这样的东西应该可以。 3)当您完成CardConversion中需要处理的事情后,请调用传递的函数来设置父级的状态值,然后应重新加载整个组件。

this.state = {
  reload: false
  ...
}

...

shouldReload() {
  this.setState({reload:!this.state.reload});
}

...

<CardConversation
  person={person}
  closeTicket={closeTicket}
  openTicketsSubmit={openTicketsSubmit}
  getPhoneNumberOpenTickets={getPhoneNumberOpenTickets}
  openTicketsReply={openTicketsReply}
  reloadParent={this.shouldReload.bind(this)}
/>

和CardConversation

const handleClick = useCallback(() => {
  getPhoneNumberOpenTickets(person);
  this.props.reloadParent();
},

答案 3 :(得分:1)

opentickets.js

创建一个函数updatePeople并在该函数中调用this.getPeopleData();
例如

updatePeople = () =>{
    this.getPeopleData();
  }

然后进入

 return this.state.people.map(person => (
            <CardConversation
                person={person}
                closeTicket={closeTicket}
                openTicketsSubmit={openTicketsSubmit}
                getPhoneNumberOpenTickets={getPhoneNumberOpenTickets}
                openTicketsReply={openTicketsReply}
                refreshPeople = {this.updatePeople}

            />
        ));

cardConversion.jsx

当您单击关闭按钮或任何使您回到openTickets的按钮时,请放置回调函数

this.props.refreshPeople();

由于您具有componentDidMount,因此每次调用componentDidMount中的内容时,它将更新信息并重新呈现

答案 4 :(得分:0)

首先,关于您没有任何数据问题,您可以检查axios以及它们如何使用post:

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    // where you can setState here
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

主要是axios正在异步处理数据。这样,一旦调用api,React将执行下一行代码。

有关如何强制更新组件的更多讨论,您可以查看这篇文章:Can you force a React component to rerender without calling setState?,它说明了如何很好地更新组件。

答案 5 :(得分:0)

据我所知,您要执行的操作是重新加载人员列表。如果是这样,您可以通过两种方式解决该问题:

  1. 在两个axios API调用中,添加.then()块并调用this.getPeopleData()
  2. .then()块中,使用setState()可以获取已添加/删除的帖子数据并更新状态,而无需重新获取人员数据。

我建议您采用选择2,因为再次获取列表将需要更多时间来获取刷新的列表。

无论哪种方式,仅将this.forceUpdate()添加到您的.then()块都不会为您提供更新的列表。它实际上不会对用户界面做任何事情。 (尽管它可以重新渲染)

答案 6 :(得分:0)

CardConversatio.jsx

import React, { useCallback, useEffect, useState } from "react";
import { Button, Accordion, Card, Form, Row, Col } from "react-bootstrap";
import axios from "axios";

const CardConversation = ({
  person,
  closeTicket,
  openTicketsSubmit,
  getPhoneNumberOpenTickets,
  openTicketsReply,
  getPhoneToCloseTicket,
}) => {
  const [conversation, setConversation] = useState([]);
  const [trigger, fireUpdate] = useState(false);

  // Handlers

  const renderConversation = useCallback(() => {
    return conversation.map(message => (
      <div key={message.date.$date + person}>
        <p>{message.from}</p>
        <p>{message.body}</p>
      </div>
    ));
  }, [conversation, person]);

  const fetchConversation = useCallback(async () => {
    try {
      const { data } = await axios.get(
        "/getconvfornum?customer_number=" + person.slice(1)
      );
      setConversation(data);
      console.log("fetch ", data);
    } catch (e) {
      console.log("error: ", e);
    }
  }, [person]);

  const handleClick = useCallback(async () => {
    await getPhoneNumberOpenTickets(person);
    setTimeout(() => fetchConversation(person), 500);
  }, [getPhoneNumberOpenTickets, person, fetchConversation]);

  const handleClickClose = useCallback(async () => {
    await getPhoneToCloseTicket(person);
  }, [person, getPhoneToCloseTicket]);


  const handleChange = useCallback(
    e => {
      openTicketsReply(e);
    },
    [openTicketsReply]
  );

  useEffect(() => {
    console.log("effect");
    fetchConversation(person);
  }, [fetchConversation, person]);

  return (
    <Accordion defaultActiveKey="0">
      <Card>
        <Card.Header>
          <Accordion.Toggle as={Button} variant="button" eventKey="0">
            Conversation {person.indexOf(person) + 1 + "    "}
            Phone number: {person}
          </Accordion.Toggle>
        </Card.Header>
        <Accordion.Collapse eventKey="0">
          <Card.Body>
            {renderConversation()}
            <Form>
              <br />
              <Form.Group as={Row} controlId="formPlaintextPassword">
                <Col sm="10">
                  <Form.Control
                    type="text"
                    placeholder="Reply"
                    name="message_body"
                    onChange={handleChange}
                  />
                </Col>
                <Button onClick={handleClick} column sm="2">
                  Reply
                </Button>
              </Form.Group>
            </Form>
            <Form>
              <Form.Group>
                <Col sm="11">
                  <Button onClick={handleClickClose} column sm="4">
                    Close Ticket
                  </Button>
                </Col>
              </Form.Group>
            </Form>
          </Card.Body>
        </Accordion.Collapse>
      </Card>
      <br />
    </Accordion>
  );
};

export default CardConversation;

OpenTickets.js

import React from "react";
import axios from "axios";

import CardConversation from './CardConversation.jsx';

export default class PersonList extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            people: [],
            send_to_number: "",
            message_body: "",
            closed: false
        };

        this.closeTicket = this.closeTicket.bind(this);
        this.openTicketsReply = this.openTicketsReply.bind(this);
        this.openTicketsSubmit = this.openTicketsSubmit.bind(this);
        this.getPhoneNumberOpenTickets = this.getPhoneNumberOpenTickets.bind(this);
        this.getPhoneToCloseTicket = this.getPhoneToCloseTicket.bind(this);
    }

    openTicketsReply = async e => {
        e.preventDefault();
        this.setState({
            message_body: e.target.value
        });
    };

    getPhoneNumberOpenTickets = async e => {
        //e.preventDefault();
        this.setState({
            send_to_number: e
        }, async () => await this.openTicketsSubmit());
    };

    getPhoneToCloseTicket = async e => {
        this.setState({
            send_to_number: e
        }, async () => this.closeTicket());
    };

    openTicketsSubmit = async e => {
        const formData = new FormData();
        formData.set("send_to_number", this.state.send_to_number.slice(1));
        formData.set("message_body", this.state.message_body);
        axios({
            method: "post",
            url: "/outgoingsms",
            data: formData,
            headers: { "Content-Type": "multipart/form-data" }
        }).then(resp => {
            this.setState({ closed: true });
        }).catch(error => console.log(error))
    };

    closeTicket = async e => {
        const formData = new FormData();
        formData.set("customernum", this.state.send_to_number.slice(1));
        axios({
            method: "post",
            url: "/closeticket",
            data: formData,
            headers: { "Content-Type": "multipart/form-data" }
        }).then(resp => {
            this.setState({ closed: true });
        }).catch(error => console.log(error))
    };


    componentDidMount() {
        this.getPeopleData();
    }

    getPeopleData = async () => {
        try {
            const { data } = await axios.get(`/getongoing?limit=10`);
            this.setState({ people: data });
        } catch (e) {
            console.log("error: ", e);
        }
    };

    render() {
        const {
            closeTicket,
            getPhoneNumberOpenTickets,
            openTicketsReply,
            getPhoneToCloseTicket
        } = this;

        return this.state.people.map(person => (
            <CardConversation
                key={person}
                person={person}
                closeTicket={closeTicket}
                getPhoneNumberOpenTickets={getPhoneNumberOpenTickets}
                openTicketsReply={openTicketsReply}
                getPhoneToCloseTicket={getPhoneToCloseTicket}
            />
        ));
    }
}