Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React function getting called on every change

I am building an isomorphic React app. The workflow I am currently working through is :

  1. User navigates to the /questions route which makes the API call server side and loads the data on the page. This calls the renderData() function like it should and loads all the questions for the user to see.
  2. User clicks add button to add new question and a modal pops up for a user to enter in the form fields and create a new question.

With every change in the modal, the renderData() function is getting called (which it shouldn't). When the user clicks the Create Question button, the renderData() function is also getting called is throwing an error because the state changes.

I can't pinpoint why the renderData() function is getting called every single time anything happens in the modal. Any ideas as to why this is happening and how to avoid it?

Main component :

import React, { Component, PropTypes } from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './QuestionsPage.scss';
import QuestionStore from '../../stores/QuestionStore';
import QuestionActions from '../../actions/QuestionActions';
import Loader from 'react-loader';
import QuestionItem from '../../components/QuestionsPage/QuestionItem';
import FloatButton from '../../components/UI/FloatButton';
import AddQuestionModal from '../../components/QuestionsPage/AddQuestionModal';

const title = 'Questions';


class QuestionsPage extends Component {

    constructor(props) {
        super(props);
        this.state = QuestionStore.getState();
        this.onChange = this.onChange.bind(this);
        this.openModal = this.openModal.bind(this);
        this.closeMOdal = this.closeModal.bind(this);
    }

  static contextTypes = {
    onSetTitle: PropTypes.func.isRequired,
  };

  componentWillMount() {
    this.context.onSetTitle(title);
    QuestionStore.listen(this.onChange);
}

componentWillUnmount() {
    QuestionStore.unlisten(this.onChange);
}

onChange(state) {
    this.setState(state);
}

openModal = () => {
    this.setState({ modalIsOpen: true});
}

closeModal = () => {
    this.setState({ modalIsOpen: false});
}

createQuestion = () => {
    const date = new Date();
    const q = this.state.question;
    q.createdAt = date;
    this.setState({ question : q });
    QuestionStore.createQuestion(this.state.question);
}

textChange = (val) => {
    const q = this.state.question;
    q.text = val;
    this.setState({ question : q });
}

answerChange = (val) => {
    const q = this.state.question;
    q.answer = val;
    this.setState({ question : q });
}

tagChange = (val) => {
    const q = this.state.question;
    q.tag = val;
    this.setState({ question : q });
}

companyChange = (val) => {
    const q = this.state.question;
    q.company = val;
    this.setState({ question : q });
}

renderData() {
    return this.state.data.map((data) => {
        return (
            <QuestionItem key={data.id} data={data} />
        )
    })
}

  render() {
    return (
      <div className={s.root}>
        <div className={s.container}>
          <h1>{title}</h1>
            <div>
                <Loader loaded={this.state.loaded} />
                <FloatButton openModal={this.openModal}/>
                <AddQuestionModal
                    open = {this.state.modalIsOpen}
                    close = {this.closeModal}
                    createQuestion = {this.createQuestion}
                    changeText = {this.textChange}
                    changeAnswer = {this.answerChange}
                    changeTag = {this.tagChange}
                    changeCompany = {this.companyChange}
                />
                { this.renderData() }
            </div>
        </div>
      </div>
    );
}

}

export default withStyles(QuestionsPage, s);

Modal Component :

import React, { Component, PropTypes } from 'react';
import QuestionStore from '../../stores/QuestionStore';
import QuestionActions from '../../actions/QuestionActions';
import Modal from 'react-modal';
import TextInput from '../UI/TextInput';
import Button from '../UI/Button';

class AddQuestionModal extends Component {
    createQuestion = () => {
        this.props.createQuestion();
    }

    closeModal = () => {
        this.props.close();
    }

    changeText = (val) => {
        this.props.changeText(val);
    }

    changeAnswer = (val) => {
        this.props.changeAnswer(val);
    }

    changeTag = (val) => {
        this.props.changeTag(val);
    }

    changeCompany = (val) => {
        this.props.changeCompany(val);
    }

    render() {
        return (
            <Modal
                isOpen={this.props.open}
                onRequestClose={this.closeModal} >

                <TextInput
                    hintText="Question"
                    change={this.changeText} />
                <TextInput
                    hintText="Answer"
                    change={this.changeAnswer} />
                <TextInput
                    hintText="Tag"
                    change={this.changeTag} />
                <TextInput
                    hintText="Company"
                    change={this.changeCompany} />
                <Button label="Create Question" onSubmit={this.createQuestion} disabled={false}/>
                <Button label="Cancel" onSubmit={this.closeModal} disabled={false}/>
            </Modal>
        );
    }
}

export default AddQuestionModal;

On click of

like image 694
erichardson30 Avatar asked Sep 17 '25 18:09

erichardson30


1 Answers

It's happening because every change causes you to call the setState method and change the state of the main component. React will call the render function for a component every time it detects its state changing.

  • The onChange event on your inputs are bound to methods on your main component
  • Each method calls setState
  • This triggers a call to render
  • This triggers a call to renderData

React allows you to change this by overriding a shouldComponentUpdate function. By default, this function always returns true, which will cause the render method to be called. You can change it so that only certain changes to the state trigger a redirect by comparing the new state with the old state.

like image 121
James Brierley Avatar answered Sep 20 '25 08:09

James Brierley