Evgeniy Ilyushin Evgeniy Ilyushin - 18 days ago 6
React JSX Question

React re-renders whole app after rendering a component

I use react and redux in my web app. It's the simple app which has 4 components, one reducer and 3 actions. After I add a new entry to list, react renders component of list (the listItem), then re-renders the whole app. What is the cause of re-rendering whole app after rendering one component?

Updated:

App container:

class App extends Component {

static propTypes = {
groups: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
};

render() {
return (<div>
<Header addGroup={this.props.actions.addGroup} />
<List groups={this.props.groups} />
</div>
);
}
}

function mapStateToProps(state) {
return { groups: state.groups };
}

function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(AppActions, dispatch) };
}

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


Reduser:

export default function groupDiseases(state = initialState, action){
switch (action.type) {
case ADD_GROUP:
return [
{
id: '',
name: action.name
},
...state
];

case DELETE_GROUP:
return state.filter(group =>
group.id !== action.id
);

case EDIT_GROUP:
return state.map(group => (group.id === action.id ? { id: action.id, name: action.name } : group));

default:
return state;
}
}


Components:

export default class Add extends Component {

static propTypes = {
addGroup: PropTypes.func.isRequired
}

componentDidMount() {
this.textInput.focus();
}

handleAdd = () => {
const name = this.textInput.value.trim();
if (name.length !== 0) {
this.props.addGroup(name);
this.textInput.value = '';
}
}

render() {
return (
<form className="add_form">
<input
type="text"
className="add__name"
defaultValue=""
ref={(input) => this.textInput = input}
placeholder="Name" />
<button
className="add__btn"
ref="add_button"
onClick={this.handleAdd}>
Add
</button>
</form>
);
}
}

export default class ListGroups extends Component {

static propTypes = {
groups: PropTypes.array.isRequired
};

render() {
let data = this.props.groups;
let groupTemplate = <div> Группы отсутствуют. </div>;
if (data.length) {
groupTemplate = data.map((item, index) => {
return (
<div key={index}>
<Item item={item} />
</div>
);
});
}

return (
<div className="groups">
{groupTemplate}
<strong
className={'group__count ' + (data.length > 0 ? '' : 'none')}>
Всего групп: {data.length}
</strong>
</div>
);
}
}

Answer

It's likely due to the fact that you are letting the <form> continue its default behavior, which is to submit to a targeted action. Take a look at the w3c spec for buttons:

http://w3c.github.io/html-reference/button.html

Specifically, a button with no type attribute will default to submit. So your button is telling the form to submit, with the target being the current page since none is provided. In your handleAdd method, you can do something like:

handleAdd = (event) => {
   event.preventDefault(); // prevent default form submission behavior
   const name = this.textInput.value.trim();
    if (name.length !== 0) {
        this.props.addGroup(name);
        this.textInput.value = '';
    }
}

Or you can modify your button to have type="button".

Comments