【问题标题】:componentDidUpdate() rendering multiple time on data fetchingcomponentDidUpdate() 在数据获取时多次渲染
【发布时间】:2019-12-04 21:08:44
【问题描述】:

我有一个组件在componentDidMount() 中同时调用两个 GET API。第二个 API(服务)的结果基于第一个 API(注册)。

另外,我使用处理程序将一些数据提交到另一个 POST API,该处理程序最终会更新第二个 GET API 中的数据。由于我的第二个 API 是在 componentDidMount() 中调用的,所以它只呈现一次。

然后我使用componentDidUpdate() 修复它以处理组件中所做的更改,并相应地在我的组件状态chatServices 中反映新添加的数据。

class ViewRegistrations extends Component{

    constructor(props) {
        super(props)

        this.state = {
             queryParam:'',
             dataReceived: [],
             isShowing: false,
             registeredDataAvailable: false,
             company_id: '',
             chatServices: []
        }
    }

    async componentDidMount(){
        const queryParam = new URLSearchParams(this.props.location.search).get('registration');
        await this.setState({
            queryParam: queryParam
        }, () => {
            this.fetchRegistrationData(queryParam);
            this.fetchChatServices(queryParam);
        });
    }

    fetchRegistrationData = async (id) => {
        axios.get(`BASE_URL+/api/company/list?id=${id}`, {headers: LocalData.headers })
        .then(res => {
            if(res.status === 200 && res.data.status === true){
                let dataReceived = this.state.dataReceived;
                let chatsReceived = res.data.data;

                dataReceived = chatsReceived;

                this.setState({
                    dataReceived,
                    registeredDataAvailable: res.data.status,
                });
            }
            else{
                const error = new Error('Invalid Request');
                this.setState({registeredDataAvailable: false});   
                throw error;
            }

        })
        .catch(err => {
            console.log(err);
        });
    }


    fetchChatServices = async (parentId) => {
        await axios.get(`BASE_URL+/api/service/list?company_id=${parentId}`, {headers: LocalData.headers})
        .then(res => {

            if(res.status === 200 && res.data.status === true) {
                let chatServices = res.data.data;
                this.setState({
                    chatServices,
                    chatDataAvailable: res.data.status,
                    company_id: parentId
                });
            }
            else{
                const error = new Error('Invalid Request');
                this.setState({chatDataAvailable: false})
                throw error;
            }

        })
        .catch(err => console.log('error occured:',err));
    }


    componentDidUpdate(prevProps, prevState){
        let chat_data = this.state.chatServices;

        if(prevState.chatServices === chat_data){
            this.fetchChatServices(this.state.queryParam)
        }
    }


    openModalHandler = async() => {
        await this.setState({
            isShowing: true
        }) 
        console.log(this.state.isShowing)
    }

    closeModalHandler = async() => {
        await this.setState({
            isShowing: false
        });
    }

    newChatService = (closemodal) => {
        this.setState({
            isShowing: closemodal,
        });
    }

    goback = () => {
        this.props.history.goBack();
    }

    render(){
        const {dataReceived, registeredDataAvailable, chatServices, isShowing, company_id} = this.state;

        return(
            <div>
            {registeredDataAvailable === true ? dataReceived.map((data) => {

                return (
                    <React.Fragment key={data.id}>
                    <Card>
                    <CardHeader>
                        <div className="form_head">
                            <h4>Company Details</h4>
                        </div>
                    </CardHeader>
                    <CardBody>
                        <Row>
                            <Col sm="12" xs="12" lg="12">
                                <fieldset className="fieldset_body">
                                <Row>
                                    <Col lg="6" sm="12" xs="12" md="6">
                                        <FormGroup>
                                            <Label>Name of Organization</Label>
                                            <Input placeholder={data.name} readOnly/>
                                        </FormGroup>
                                    </Col>
                                    <Col lg="6" sm="12" xs="12" md="6">
                                        <FormGroup>
                                            <Label>Name of Authority</Label>
                                            <Input placeholder={data.authority} readOnly/>
                                        </FormGroup>
                                    </Col>
                                </Row>
                                <Row>
                                    <Col lg="6" sm="12" xs="12" md="6">
                                        <FormGroup>
                                            <Label>Email</Label>
                                            <Input placeholder={data.email} readOnly/>
                                        </FormGroup>
                                    </Col>
                                    <Col lg="6" sm="12" xs="12" md="6">
                                        <FormGroup>
                                            <Label>Contact Number</Label>
                                            <Input placeholder={data.contact} readOnly/>
                                        </FormGroup>
                                    </Col>
                                </Row>
                                </fieldset>
                            </Col>
                        </Row>
                    </CardBody>
                </Card>       

                <Card>
                    <CardHeader>
                        <Row>
                            <Col lg="6" md="6" sm="12" xs="12">
                                <h4>Chat Services</h4>
                            </Col>
                            <Col lg="6" md="6" sm="12" xs="12">
                                <Button className="pull-right" onClick={this.openModalHandler}>Add Chat Services</Button>
                            </Col>
                        </Row>
                    </CardHeader>
                    <CardBody>
                        {
                            chatServices.length ? (
                                <ChatServicesLists chatServices={chatServices} company_id={company_id} />  
                            )
                            : 
                            (
                                <Row>
                                    <Col xs="12" sm="12" md="12" lg="12">
                                        <p className="text-center">Chat Services Not Available !</p>
                                    </Col>
                                </Row>
                            )
                        }
                    </CardBody>
    ........
}

我的问题是我的组件现在被渲染了 3-4 次;一旦安装了组件并添加了新数据。在这两种情况下,它都会渲染大约 3-4 次。

请帮助了解相关问题并避免这种不必要的组件渲染。

【问题讨论】:

  • 嗨,我的回答有意义吗?

标签: reactjs


【解决方案1】:
componentDidUpdate(prevProps, prevState){
    let chat_data = this.state.chatServices;

    if(prevState.chatServices.length !== chat_data.length){
        this.setState({chatServices:chat_data})
    }
}

这样修改,会检查chatServices的新旧数组长度

【讨论】:

  • 这样我的数据就不会反射回我的状态,因此不会渲染新添加的数据,组件仍然至少渲染 5 次。
  • 然后使用 componentWillReceiveProps 生命周期
  • 只是为了更新,componentWillReceiveProps() 已被弃用,现在是 componentDidUpdate(prevProps, prevState)
【解决方案2】:

代码中的 setState 语句过多。

当我从 api 调用中获取所有数据时,我会尝试只使用一次 setState。

一个例子是这样的:

  state = {
    user: null,
    posts: []
  };

  async componentDidMount() {
    const userId = this.props.userId;

    const userResponse = await axios.get(
      `https://jsonplaceholder.typicode.com/users/${userId}`
    );

    const postsResponse = await axios.get(
      `https://jsonplaceholder.typicode.com/posts?userId=${userId}`
    );

    this.setState({
      user: userResponse.data,
      posts: postsResponse.data
    });
  }

这只会导致 2 次渲染。

Codesandbox

另外提一下,在setState回调函数中调用api似乎不是个好主意。

  await this.setState({
            queryParam: queryParam
        }, () => {
            this.fetchRegistrationData(queryParam);
            this.fetchChatServices(queryParam);
        });

【讨论】:

    猜你喜欢
    • 2021-12-06
    • 2018-03-04
    • 2022-01-02
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    相关资源
    最近更新 更多