最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Component not re-rendering after onChange event - Stack Overflow

programmeradmin1浏览0评论

I've checked the previous answer on different topics about re-rendering but couldn't find a proper way to fix this. I am trying to re-render a ponent after the onChange event is fired on the select box.

I have a userlist with 5 users and I separated them into genders array. So I have a males array and a females array. I am trying to show the selected gender user list after the onChange event.

I tried to use the 'key' attr in ponent but it didn't work.

here is my UserList container:

import React, { Component } from "react";
import ReactDOM from "react-dom";

import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import List from '../ponents/List.jsx'

class UserList extends Component {

    constructor(props) {
         super(props);
     }

    renderUser = (toMap) => {
        console.log(toMap);
    return (
            <List key = {toMap.length} users = {toMap}/>
        );
  }

    renderSelect = () => {
    return (
            <select id="gender" onChange={this.handleChange}>
        <option value="select">Select a gender</option>
        <option value="males">Males</option>
        <option value="females">Females</option>
      </select>
        );
  }

    handleChange = (e) => {
        const {userList,males,females} = this.props;
        const gender = e.target.value;

        if(gender == 'males'){
            return this.renderUser(males);
        }else if(gender == 'females'){
            return this.renderUser(females);
        }
        return this.renderUser(userList);
    }

  render() {
        const {isLoading,error,userList} = this.props;

         return (
             <div>
                 {this.renderSelect()}
           <ul>
                    {this.renderUser(userList)}
           </ul>
                </div>
     );
    }
}

export default connect(mapStateToProps)(UserList);

here is my List Component:

import React from 'react';

const List = ({users}) => (
    <ul>
        {users.map( (user,index) => (
          <li key = {index} >{user.email}</li>
        ))}
    </ul>
);

export default List;

the props (users) are passing correctly when I check the console in handleChange but can't quite a visual result.

I've checked the previous answer on different topics about re-rendering but couldn't find a proper way to fix this. I am trying to re-render a ponent after the onChange event is fired on the select box.

I have a userlist with 5 users and I separated them into genders array. So I have a males array and a females array. I am trying to show the selected gender user list after the onChange event.

I tried to use the 'key' attr in ponent but it didn't work.

here is my UserList container:

import React, { Component } from "react";
import ReactDOM from "react-dom";

import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import List from '../ponents/List.jsx'

class UserList extends Component {

    constructor(props) {
         super(props);
     }

    renderUser = (toMap) => {
        console.log(toMap);
    return (
            <List key = {toMap.length} users = {toMap}/>
        );
  }

    renderSelect = () => {
    return (
            <select id="gender" onChange={this.handleChange}>
        <option value="select">Select a gender</option>
        <option value="males">Males</option>
        <option value="females">Females</option>
      </select>
        );
  }

    handleChange = (e) => {
        const {userList,males,females} = this.props;
        const gender = e.target.value;

        if(gender == 'males'){
            return this.renderUser(males);
        }else if(gender == 'females'){
            return this.renderUser(females);
        }
        return this.renderUser(userList);
    }

  render() {
        const {isLoading,error,userList} = this.props;

         return (
             <div>
                 {this.renderSelect()}
           <ul>
                    {this.renderUser(userList)}
           </ul>
                </div>
     );
    }
}

export default connect(mapStateToProps)(UserList);

here is my List Component:

import React from 'react';

const List = ({users}) => (
    <ul>
        {users.map( (user,index) => (
          <li key = {index} >{user.email}</li>
        ))}
    </ul>
);

export default List;

the props (users) are passing correctly when I check the console in handleChange but can't quite a visual result.

Share Improve this question asked Aug 15, 2019 at 8:51 Ekin AlcarEkin Alcar 1353 silver badges7 bronze badges 5
  • 1 You should store your selection in state. Your ponents will rerender after state changes. – Sasha Commented Aug 15, 2019 at 8:55
  • 1 Hi Ekin, could you solve this issue ? – sebastienbarbier Commented Sep 12, 2019 at 12:19
  • hi @sebastienbarbier yes I updated the state. – Ekin Alcar Commented Sep 12, 2019 at 17:49
  • Awesome, please feel free to mark your question as answered when you have a moment :). Have a great day. – sebastienbarbier Commented Sep 13, 2019 at 10:44
  • I am so sorry marked as accepted now! – Ekin Alcar Commented Sep 13, 2019 at 15:27
Add a ment  | 

2 Answers 2

Reset to default 4

State and Lifecycle

You should use state / setState as a way to trigger a rendering on react.

setState() enqueues changes to the ponent state and tells React that this ponent and its children need to be re-rendered with the updated state.

Main idea here is to store gender value in state, as we want to render when this value is changed

  1. Add a initial state on your contructor

    constructor(props) {
         super(props);
         this.state = {
             gender: []
         }
     }
    
  2. Update onChange event, using setState() with a new value. This function will notify asynchroniously react about the need to rerender. You need to refactor a bit your logic to clean you change handler with just updating state. Keep in mind setState is async, might be source of misunderstanding.

      handleChange = (e) => {
         setState({gender: e.target.value});
     }
    
  3. Final version should look something like this :

    import React, { Component } from "react";
    import ReactDOM from "react-dom";
    
    import { connect } from 'react-redux';
    import PropTypes from 'prop-types';
    
    import List from '../ponents/List.jsx'
    
    class UserList extends Component {
    
      constructor(props) {
        super(props);
        this.state = { gender: null };
      }
    
      renderUser = (toMap) => {
        return (
            <List 
                key = {toMap.length} 
                users = {toMap.filter(user => this.state.gender ? user.gender === this.state.gender : true)}/>
          );
      }
    
      renderSelect = () => {
        return (
          <select id="gender" onChange={this.handleChange}>
            <option value="select">Select a gender</option>
            <option value="males">Males</option>
            <option value="females">Females</option>
          </select>
        );
      }
    
      handleChange = (e) => {
        this.setState({ gender: e.target.value})
      }
    
      render() {
        const {isLoading,error,userList} = this.props;
    
        return (
          <div>
            { this.renderSelect() }
            <ul>
              { this.renderUser(userList) }
            </ul>
          </div>
        );
      }
    }
    

    renderUser() will perform a filter based on selected gender. No need to store males and females as performance should be fine for most case.

Here is a working example of your code : https://codesandbox.io/s/new-wkgu6

you are not setting state anywhere because of which ponent is not rendering again

setState() will always lead to a re-render unless shouldComponentUpdate() returns false.

More information on setState api can be found here

https://reactjs/docs/react-ponent.html#setstate

发布评论

评论列表(0)

  1. 暂无评论