简体   繁体   English

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

[英]React: re render componet after button click

How do I make page refresh or reender content in page after I click submit button?单击提交按钮后,如何使页面刷新或重新呈现页面中的内容? I've trying to put window.location.reload() (I know that not the React way, this.forceUpdate() have same result) in submit functions( closeTicket() , openTicketSubmit() ) but POST request don't get response我试图将window.location.reload() (我知道不是 React 方式, this.forceUpdate()具有相同的结果)放入提交函数( closeTicket()openTicketSubmit() )但 POST 请求没有得到回复

OpenTickets.js 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 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;

A simple way to re-render would be to change the state variable on the submission of the Axios request causing the component to re-render automatically.重新渲染的一种简单方法是在提交 Axios 请求时更改状态变量,从而导致组件自动重新渲染。 Example:例子:

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

You can make the component re-render by updating its state ( after the POST ) :您可以通过更新组件的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();
  })
};

React will rerender components once the state changes, which means that what you need is to change the state once the submit button is clicked.一旦状态发生变化,React 将重新渲染组件,这意味着您需要在单击提交按钮后更改状态。 Since the submit button is inside the PersonList component and you also want to reload PersonList, you want to change the state of PersonList when the submit button is clicked.由于提交按钮位于 PersonList 组件内,并且您还希望重新加载 PersonList,因此您希望在单击提交按钮时更改 PersonList 的状态。

Here is what you might want to do: 1) add a 'reload' state to PersonList, defaulting it to false.以下是您可能想要做的: 1) 将“重新加载”状态添加到 PersonList,默认为 false。 This will tell the component if you need to reload or not.这将告诉组件您是否需要重新加载。 2) pass a function that sets the state of PersonList's reload value into the child component, in this case CardConversion. 2) 将设置 PersonList 的重载值状态的函数传递给子组件,在本例中为 CardConversion。 something like this.setState({reload:!this.state.reload}) should do.像 this.setState({reload:!this.state.reload}) 应该做的事情。 3) when you finish handling what you need to handle within CardConversion, call your passed function to set the parent's state value, and the whole component should 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)}
/>

and on CardConversation在 CardConversation 上

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

in opentickets.jsopentickets.js

create a function updatePeople and in that function call this.getPeopleData();创建一个函数 updatePeople 并在该函数中调用this.getPeopleData();
eg例如

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

then in然后在

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

            />
        ));

in cardConversion.jsxcardConversion.jsx

when you click the close button or whichever button gets you back to openTickets, put the callback function当您单击关闭按钮或任何按钮让您回到 openTickets 时,放置回调函数

this.props.refreshPeople();

because you have componentDidMount, everytime you call whatever is in componentDidMount, it will update the information and re render it因为你有componentDidMount,每次你调用componentDidMount中的任何东西,它都会更新信息并重新渲染它

First of all, regarding you are not getting any data issue, you can check axios , and how they use post:首先,关于您没有收到任何数据问题,您可以检查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);
  });

Mainly axios are handling the data asynchronously.主要是 axios 异步处理数据。 By that, once you call the api, React will executes next line of code.这样,一旦你调用了 api,React 就会执行下一行代码。

For more discussion of how to force update the component, you can check this post: Can you force a React component to rerender without calling setState?有关如何强制更新组件的更多讨论,您可以查看这篇文章: Can you force a React component to rerender without calling setState? , which explain how to update component very well. ,它很好地解释了如何更新组件。

As far as I can see, what you're trying to do is reload the people list.据我所知,您要做的是重新加载人员列表。 If that's the case, you can solve it in two ways:如果是这种情况,您可以通过两种方式解决它:

  1. In both axios API calls, add .then() block and call this.getPeopleData() .在两个axios API 调用中,添加 .then .then()块并调用this.getPeopleData()
  2. Instead of re-fetching people's data, you get the added/deleted post data and update state in the .then() block with setState() .您无需重新获取人们的数据,而是使用setState().then()块中获取添加/删除的帖子数据并更新状态。

I suggest you to adopt Option 2, because fetching the list again will require more time for you to get the refreshed list.我建议您采用选项 2,因为再次获取列表将需要更多时间来获取刷新的列表。

Either way, just adding this.forceUpdate() to your .then() block will not give you the updated list.无论哪种方式,只需将this.forceUpdate()添加到您的 .then( .then()块中都不会为您提供更新的列表。 It won't do anything actually to the UI.它实际上不会对 UI 做任何事情。 (though it makes it re-render) (虽然它使它重新渲染)

CardConversatio.jsx 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 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}
            />
        ));
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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