为什么当 Redux 状态改变时我的输入值没有更新?

时间:2021-06-24 13:37:11

标签: javascript reactjs redux

我的组件接收到正确的 props(使用“listDescAdd”后应该为“null”),但输入中的值没有改变。

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
import { listDescAdd, listDescEdit, listRemove, listDescCurrent  } from 'redux/actions';
import { connect } from 'react-redux';
import FormContext from 'context/FormContext';
import plus from 'img/icons/plus.svg';
import minus from 'img/icons/minus.svg';
import Select from 'react-select';
import { objt } from 'utils';

export class ListInputDescriptionItem extends Component {
  constructor (props) {
    super(props);
    this.state = { description: '', training: '' };
    this.handleChangeTraining = this.handleChangeTraining.bind(this);
    this.handleChangeDescription = this.handleChangeDescription.bind(this);
    this.handleEditDescription = this.handleEditDescription.bind(this);
    this.handleEditTraining = this.handleEditTraining.bind(this);
    this.handleAdding = this.handleAdding.bind(this);
    this.currentTextInput = React.createRef();
  }

  getRequired () {
    if (this.props.required === true) {
      return <span className="tw-font-semibold tw-text-red-500 tw-text-sm tw-ml-2">{this.props.t('required')}</span>;
    }
  }

  // handle input text change
  handleChangeTraining (data, context) {
    if (data) {
      var training = data.value;
    } else {
      var training = undefined;
    }
    this.props.listDescCurrent(this.props.name, this.props?.input?.[context.name]?.[this.props.name + '_current']?.value, training, context.name)
  }

  handleChangeDescription (e, context) {
    var { value } = e.target;
    this.props.listDescCurrent(this.props.name, value, this.props?.input?.[context.name]?.[this.props.name + '_current']?.training, context.name)
  }

  // handle sending new entry
  // clear state when sending
  handleAdding (context) {

    if (this.props?.input?.[context.name]?.[this.props.name + '_current']?.value && this.props?.input?.[context.name]?.[this.props.name + '_current']?.training) {
      this.props.listDescAdd(
        this.props.name, 
        this.props?.input?.[context.name]?.[this.props.name + '_current']?.value,
        this.props?.input?.[context.name]?.[this.props.name + '_current']?.training,
        context.name);
        this.currentTextInput.current.value = '';
    }
  }

  // handle sending on enter
  // use state and handleAdding
  _handleKeyDown (e, context) {
    if (e.key === 'Enter') {
      if (this.props?.input?.[context.name]?.[this.props.name + '_current']?.value && this.props?.input?.[context.name]?.[this.props.name + '_current']?.training) {
        this.props.listDescAdd(
          this.props.name, 
          this.props?.input?.[context.name]?.[this.props.name + '_current']?.value,
          this.props?.input?.[context.name]?.[this.props.name + '_current']?.training,
          context.name);
          this.forceUpdate();
      }
    }
  }

  // handle edit of existing value
  handleEditDescription (e, context) {
    this.props.listDescEdit(this.props.name, e.target.value, this.getValue(context), context.name, this.props.item.id);
  }

  handleEditTraining (data, context) {
    this.props.listDescEdit(this.props.name, this.getValueDescription(context), ((data && data.value) || null), context.name, this.props.item.id);
  }

  getValue (context = null, current = false) {
    if(current === true) {
      if(this.props?.input?.[context.name]?.[this.props.name + '_current']?.training) {
        return this.getOptions().filter(option => option.value === this.props?.input?.[context.name]?.[this.props.name + '_current']?.training)[0];
      }
      return null;
    }
    if (context === null) {
      if (this.state.training) {
        return this.getOptions().filter(option => option.value === this.state.training)[0];
      } else {
        return null;
      }
    }
    if (this.props.input && this.props.input[context.name] && this.props.input[context.name][this.props.name] && this.props.input[context.name][this.props.name].filter(i => i.id === this.props.item.id).length !== 0) {
      return this.getOptions().filter(option => {
        return option.value === this.props.input[context.name][this.props.name].filter(i => i.id === this.props.item.id)[0].training;
      })[0];
    } else {
      return null;
    }
  }

  getValueDescription (context, current = false) {
    if(current === true) {
      return this.props?.input?.[context.name]?.[this.props.name + '_current']?.value;
    }
    if (this.props.input && this.props.input[context.name] && this.props.input[context.name][this.props.name] && this.props.input[context.name][this.props.name] && this.props.input[context.name][this.props.name].filter(i => i.id === this.props.item.id).length !== 0) {
      return this.props.input[context.name][this.props.name].filter(i => i.id === this.props.item.id)[0].value;
    } else {
      return undefined;
    }
  }

  getOptions () {
    var options = this.props.options ? this.props.options.map((option) => {
      return {
        value: option.id,
        label: objt(option)

      };
    }) : {};
    return options;
  }

  renderInput (context) {
    if (this.props.type === 'add') {
      return (
        <div className="tw-flex tw-flex-row tw-w-full">
          <div className="tw-flex tw-flex-col tw-flex-1">
            <input
              key={999999}
              ref={this.currentTextInput}
              type={this.props.type}
              id={this.props.name}
              placeholder="Description"
              className="focus:tw-outline-none focus:tw-shadow-outline tw-bg-gray-300   tw-py-2 tw-px-3 tw-flex-1"
              style={{ height: '38px' }}
              value={this.getValueDescription(context, true)}
              onChange={(e) => {
                this.handleChangeDescription(e, context);
              }}
              onKeyDown={(e) => {
                this._handleKeyDown(e, context);
              }} />
            <Select
              key={9999999}
              options={this.getOptions()}
              isClearable={true}
              value={this.getValue(context, true)}
              name={this.props.name}
              onChange={(data) => {
                this.handleChangeTraining(data, context);
              }}
              styles={{
                control: (provided, state) => ({
                  ...provided,
                  backgroundColor: '#e2e8f0'
                }),
                menu: (provided, state) => ({
                  ...provided,
                  zIndex: '9999'
                })
              }}
              classNamePrefix="select" />
          </div>
          <div onClick={(e) => {
            this.handleAdding(context);
          }} className="tw-bg-green-500  tw-cursor-pointer tw-flex tw-flex-row tw-justify-center tw-items-center tw-h-full" style={{ width: '38px' }}>
            <img src={plus} className="w-1/2" />
          </div>
        </div>
      );
    } else {
      return (
        <div className="tw-flex tw-flex-row tw-w-full">
          <div className="tw-flex tw-flex-col tw-flex-1">
            <input
              type={this.props.type}
              id={this.props.name}
              placeholder="Description"
              className="tw-text-black focus:tw-outline-none focus:tw-shadow-outline tw-bg-gray-300   tw-py-2 tw-px-3 tw-flex-1"
              style={{ height: '38px' }}
              value={this.getValueDescription(context)}
              onChange={(e) => { this.handleEditDescription(e, context); }}
            />
            <Select
              options={this.getOptions()}
              isClearable={true}
              value={this.getValue(context)}
              name={this.props.name}
              onChange={(data) => {
                this.handleEditTraining(data, context);
              }}
              styles={{
                control: (provided, state) => ({
                  ...provided,
                  backgroundColor: '#e2e8f0'
                }),
                menu: (provided, state) => ({
                  ...provided,
                  zIndex: '9998',
                  color: 'black'
                }),
                menuList: (provided, state) => ({
                  ...provided,
                  zIndex: '9999'
                })
              }}
              classNamePrefix="select" />
          </div>
          <div onClick={(e) => {
            this.props.listRemove(this.props.name, context.name, this.props.item.id);
          }} className="tw-bg-red-500  tw-cursor-pointer tw-flex tw-flex-row tw-justify-center tw-items-center tw-h-full" style={{ width: '38px' }}>
            <img src={minus} className="w-1/2" />
          </div>
        </div>
      );
    }
  }

  render () {
    return (
      <FormContext.Consumer>
        {context =>
          <div className={`tw-flex tw-flex-col ${this.props.size} tw-mb-3`}>
            <div className="tw-flex tw-flex-row tw-w-full">
              {this.renderInput(context)}
            </div>
          </div>
        }
      </FormContext.Consumer>

    );
  }
}

ListInputDescriptionItem.defaultProps = {
  size: 'w-full',
  required: true,
  type: 'text'
};

ListInputDescriptionItem.propTypes = {
  name: PropTypes.string.isRequired,
  title: PropTypes.string,
  size: PropTypes.string.isRequired,
  required: PropTypes.bool,
  type: PropTypes.string,
  t: PropTypes.func.isRequired
};

const mapStateToProps = ({ errors, input }, ownProps) => {
  return {
    errors: errors,
    input: input
  };
};

export default connect(mapStateToProps, { listDescAdd, listDescEdit, listRemove, listDescCurrent })(withTranslation(['input'])(ListInputDescriptionItem));
import { HANDLE_CHANGE, CLEAR_FORM, LIST_ADD, LIST_EDIT, LIST_REMOVE, LIST_DESC_ADD, LIST_DESC_EDIT, LIST_CURRENT, LIST_DESC_CURRENT } from '../actionTypes';
import produce from 'immer';

const input = (state = { listId: 0 }, action) => {
  switch (action.type) {
    case HANDLE_CHANGE: {
      const { name, value, form } = action.payload;
      if (!state[form]) {
        return produce(state, draft => {
          draft[form] = {};
          draft[form][name] = value;
        });
      } else {
        return produce(state, draft => {
          draft[form][name] = value;
        });
      }
    }
    case LIST_CURRENT: {
      const { name, value, form } = action.payload;
      if (!state[form]) {
        return produce(state, draft => {
          draft[form] = {};
          draft[form][name + '_current'] = value;
          draft.listId++;
        });
      } else {
        return produce(state, draft => {
          draft[form][name + '_current'] = value;
        });
      }
    }
    case LIST_ADD: {
      const { name, value, form } = action.payload;
      if (!state[form]) {
        return produce(state, draft => {
          draft[form] = {};
          draft[form][name] = [{ id: draft.listId, value: value }];
          draft[form][name + '_current'] = '';
          draft.listId++;
        });
      } else {
        return produce(state, draft => {
          if (!draft[form][name]) {
            draft[form][name] = [];
          }
          draft[form][name].unshift({ id: draft.listId, value: value });
          draft[form][name + '_current'] = '';
          draft.listId++;
        });
      }
    }
    case LIST_EDIT: {
      const { name, value, id, form } = action.payload;
      return produce(state, draft => {
        draft[form][name] = draft[form][name].map(item => {
          if (item.id === id) {
            item.value = value;
          }
          return item;
        });
      });
    }
    case LIST_REMOVE: {
      const { name, id, form } = action.payload;
      return produce(state, draft => {
        draft[form][name] = draft[form][name].filter(item => item.id !== id);
      });
    }
    case LIST_DESC_CURRENT: {
      const { name, value, training, form } = action.payload;
      if (!state[form]) {
        return produce(state, draft => {
          draft[form] = {};
          draft[form][name + '_current'] = {training, value};
        });
      } else {
        return produce(state, draft => {
          draft[form][name + '_current'] = {training, value};
        });
      }
    }
    case LIST_DESC_ADD: {
      const { name, value, training, form } = action.payload;
      if (!state[form]) {
        return produce(state, draft => {
          draft[form] = {};
          draft[form][name] = [{ id: draft.listId, training: training, value: value }];
          draft[form][name + '_current'] = null;
          draft.listId++;
        });
      } else {
        return produce(state, draft => {
          if (!draft[form][name]) {
            draft[form][name] = [];
          }
          draft[form][name].unshift({ id: draft.listId, training: training, value: value });
          draft[form][name + '_current'] = null;
          draft.listId++;
        });
      }
    }
    case LIST_DESC_EDIT: {
      const { name, value, training, id, form } = action.payload;
      return produce(state, draft => {
        draft[form][name] = draft[form][name].map(item => {
          if (item.id === id) {
            item.value = value;
            item.training = training;
          }
          return item;
        });
      });
    }
    case CLEAR_FORM: {
      const { form } = action.payload;
      return produce(state, draft => {
        delete draft[form];
      });
    }
    default:
      return state;
  }
};

export default input;

因此,在输入(第一个)中,使用“listDescAdd”将“当前”输入重置为空后,输入中的值保持不变。但是,当我检查时,它显示文本输入收到了正确的道具,但没有更新显示的值。

知道如何解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

尝试使用 value={() => this.getValueDescription(context)}