Search code examples
reactjsreduxredux-form

Updating Item Listing using React, Redux. and Redux Form


How do I update the horse listing after the add horse action is fully done?

I think that the reloadHorseList in CreateHorse is running before createHorse actions is completely done so sometimes I see new horse in list and sometimes not. A full reload shows an update always.

Horses Component

...
import { getHorses } from '../../actions';
import ListHorses from './ListHorses';
import CreateHorse from './forms/createHorseForm';

class Horses extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      ...
    };
    this.reloadHorseList = this.reloadHorseList.bind(this);
  }

  componentDidMount() {
     this.reloadHorseList();
  }

  reloadHorseList() {
    this.props.getHorses(this.props.current_user.selected_stable);
  }

  render() {
    return (
      <div className="content page-content-wrapper1">

        <CreateHorse
          current_user={this.props.current_user}
          reloadHorseList={this.reloadHorseList}
        />
        <ListHorses
          current_user={this.props.current_user}
          horses={this.props.horses}
        />
      </div>
    );
  }
}

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

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

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

Create Horse Form

...
import { Field, reduxForm, getFormValues } from 'redux-form';
import {
  createHorse,
  getHorseSelect,
  updateHorseCount
} from '../../../actions';
import { connect } from 'react-redux';

const renderField = (...
);

class CreateHorse extends Component {
  constructor(props) {
    super(props);
      this.state = {
      ...
    };
    this.setMessage = this.setMessage.bind(this);
  }


  onSubmit(props) {
    //let p = this.props.reloadHorseList;
    try {
      this.props.createHorse(props, this.setMessage);

      //running before I have finished creating my horse
      this.props.reloadHorseList();

    } catch (err) {
      ...
    }
  }


  render() {
    const { handleSubmit } = this.props;

    return (
      <div>
        ...
        {this.state.displayHorseCreateForm && (
          <div>
            <h4 className="header-content">Add Horse</h4>
            <p> * required field</p>

            <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>

              // fields here

              <button type="submit" className="btn btn-primary">
                Submit
              </button>
            </form>
          </div>
        )}
      </div>
    );
  }
}
function validate(values) {
 ...
}

function mapStateToProps(state) {
  ---
}

export default connect(mapStateToProps, {
  createHorse,
  getHorseSelect,
  updateHorseCount
})(
  reduxForm({
    form: 'HorseCreatetForm',
    initialValues: {
      ...
    },
    validate
  })(CreateHorse)
);

//create horse action
export const createHorse = (props, setMessage) => async dispatch => {
  try {
    const request = await axios.post(`/api/horse/create`, props);
    return {
      type: CREATED_HORSE,
      payload: request.data
    };
  } catch (err) {
   ...
  }
};

ListHorses

...
import { deleteHorse } from '../../actions';

class HorsesList extends React.Component {

  render() {
    let horses = this.props.horses;
    let horseCount = this.props.horse_count;
    return (
      <div className="content">
        horse count: {horseCount}
        <ul className="list-inline box-body">
          {horseCount > 0 &&
            horses.map((horse, key) => (
              <li key={key}>
                ...//listing here
              </li>
            ))}
        </ul>
      </div>
    );
  }
}

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

function mapDispatchToProps(dispatch) {
  return bindActionCreators(
    {
      ...
    },
    dispatch
  );
}

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

Solution

  • The solution that worked for me is to send a callback to the CreateHorse component to send to the createHorse action which runs Horse components action to getHorses.

    class Horses extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          horses: this.props.horses,
        };
        this.reloadHorses = this.reloadHorses.bind(this);
      }
    
      componentDidMount(prevProps) {
        this.props.getHorses(this.props.current_user.selected_stable);
      }
    
      reloadHorses = () => {
        this.props.getHorses(this.props.current_user.selected_stable);
      };
    
      ...
    
      <CreateHorse
        current_user={this.props.current_user}
        reloadHorses={this.reloadHorses}
      />
      <ListHorses
        horses={this.props.horses}
      />
    
    ... 
    
    function mapStateToProps(state) {
      return {
        horses: state.horses
      };
    }
    
    function mapDispatchToProps(dispatch) {
      return bindActionCreators(
        {
          getHorses: getHorses
        },
        dispatch
      );
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Horses);
    

    then in CreateHorse component

    onSubmit(props) {
    
          this.props.createHorse(props, this.setMessage, this.props.reloadHorses);
    
        }
      }
    

    Then in the createHorse action

    export const createHorse = (
      props,
      setMessage,
      reloadHorses
    ) => async dispatch => {
      try {
        const request = await axios.post(`/api/horse/create`, props);
    
        reloadHorses();
    
        return {
          type: CREATED_HORSE,
          payload: request.data
        };
      } catch (err) {
       ...
      }
    };