Как закрыть модальное диалоговое окно при изменении состояния в React-Redux? - PullRequest
0 голосов
/ 01 мая 2019

Как правило, я хочу изменить состояние пользовательского интерфейса в компоненте, когда глобальное состояние было изменено в Redux-Store.

Мой сценарий выглядит следующим образом:

  1. Показатьмодальная форма, когда пользователь нажимает кнопку «Добавить учащегося»
  2. Показывать «Сохранение ...», когда пользователь нажимает кнопку «Сохранить»
  3. Если возникает ошибка, диалоговое окно должно оставаться открытым ипоказать ошибку
  4. Если вставка в порядке, диалог должен быть закрыт автоматически

enter image description here

Я набрал первые 3 очка, но я застрял в 4-й точке и не знаю, как реализовать функцию Close после успешной вставки.

Я хотел бы запускать следующий пример кода всякий раз, когда isSubmitting / error была измененав Redux-магазине.Но я не знаю, где его запустить.Я пытался поместить его в метод render (), но он не работает, и я больше не мог открыть диалоговое окно.

Код для проверки и закрытия модального

if (isSubmitting === false && error === null)
     this.setState({ add: false });

Я не хочу поднимать это состояние пользовательского интерфейса (например, IsModalOpen - bool) в хранилище Global Redux.Я уже поместил состояние пользовательского интерфейса isSubmitting в Redux, и я не хочу продолжать добавлять состояния пользовательского интерфейса в Redux Store.

Не могли бы вы предложить мне, как я могу закрыть диалоговое окно после успешной вставки?

Я поместил образец кода в CodeSandbox, и он здесь

Редуктор

const initialState = {
      isSubmitting: false,
      error: null,
      student: null
    };

function rootReducer(state = initialState, action) {
  switch (action.type) {
    case "STUDENT_ADD_BEGIN": {
      return {
        ...state,
        isSubmitting: true
      };
    }
    case "STUDENT_ADD_SUCCESS": {
      return {
        ...state,
        student: action.payload,
        error: null,
        isSubmitting: false
      };
    }
    case "STUDENT_ADD_ERROR": {
      return {
        ...state,
        isSubmitting: false,
        error: action.error,
        student: null
      };
    }
    default:
      return state;
  }
}

export default rootReducer;

Контейнер /Страница

class addStudentPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dataList: [],
      add: false,
      edit: false,
      dataItem: {}
    };
  }

  getInitialState() {
    return {
      id: "",
      name: "TTCG"
    };
  }

  componentDidMount() {
    this.setState({
      dataItem: this.getInitialState()
    });
  }

  toggleAdd = () => {
    this.setState(prevState => ({
      add: !prevState.add
    }));
  };

  showAddNew = () => {
    this.toggleAdd();

    this.setState({
      dataItem: this.getInitialState()
    });
  };

  updateItemState = event => {
    const field = event.target.name;
    const value = event.target.value;
    let item = this.state.dataItem;

    item[field] = value;

    return this.setState({ dataItem: item });
  };

  handleAddNew = () => {
    let item = this.state.dataItem;
    item["id"] = uuid.v4();
    console.info(item);
    this.props.addStudentAction(item);
  };

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

    return (
      <Container>
        <h1>Students</h1>
        <Button onClick={this.showAddNew} color="link">
          Add New Student
        </Button>
        {this.state.add && (
          <AddStudent
            toggle={this.toggleAdd}
            modal={this.state.add}
            item={this.state.dataItem}
            onChange={this.updateItemState}
            onAddNew={this.handleAddNew}
            isSubmitting={isSubmitting}
            error={error}
          />
        )}
        {this.props.student && (
          <h6>You have added a new student named: {this.props.student.name}</h6>
        )}
      </Container>
    );
  }
}

const mapStateToProps = state => {
  return {
    isSubmitting: state.studentReducer.isSubmitting,
    error: state.studentReducer.error,
    student: state.studentReducer.student
  };
};

const mapDispatchToProps = {
  addStudentAction: item => addStudentAction(item)
};

Модальная форма

export default class StudentAdd extends Component {
  render() {
    const {
      modal,
      toggle,
      item,
      onChange,
      onAddNew,
      isSubmitting,
      error
    } = this.props;

    return (
      <Modal isOpen={modal} toggle={toggle} centered>
        <ModalHeader toggle={toggle}>Add New Student</ModalHeader>
        <ModalBody>
          {error && <Alert color="danger">{error}</Alert>}
          <Form>
            <FormGroup>
              <Label for="Name">Name</Label>
              <Input
                type="text"
                name="name"
                id="Name"
                value={item.name}
                onChange={onChange}
              />{" "}
              type 'error' to simulate error
            </FormGroup>
          </Form>
        </ModalBody>
        <ModalFooter>
          <Button color="primary" onClick={onAddNew} disabled={isSubmitting}>
            {isSubmitting ? "Saving..." : "Save"}
          </Button>{" "}
          <Button color="secondary" onClick={toggle}>
            Cancel
          </Button>
        </ModalFooter>
      </Modal>
    );
  }
}

ОБНОВЛЕНИЯ

Это может быть достигнуто с помощью componentDidUpdate метод жизненного цикла, как показано ниже: пожалуйста, будьте внимательны, чтобы правильно проверить реквизиты и состояния перед выводом состояния.

componentDidUpdate(prevProps) {
    const { isSubmitting, error } = this.props;
    if (isSubmitting !== prevProps.isSubmitting || error !== prevProps.error) {
      if (isSubmitting === false && error === null)
        this.setState({ add: false });
    }
  }

Или вы можете использовать getDerivedStateFromProps метод жизненного цикла для пересчета реквизитов.Но мне было трудно пользоваться чем componentDidUpdate.

1 Ответ

0 голосов
/ 02 мая 2019

Достигнуть этого немного сложнее и неуклюже, но вы все равно можете вызвать такое поведение следующим образом:

Использование Promise в вашем действии:

export const addStudentAction = item => {
    return function(dispatch) {
        dispatch({ type: 'STUDENT_ADD_BEGIN' });

        setTimeout(() => {
            if (item.name !== 'error') {
                // HERE
                Promise.resolve(
                    dispatch({ type: 'STUDENT_ADD_SUCCESS', payload: item })
                );
                dispatch(closeModal('AddStudentModal'));
            } else {
                // HERE
                Promise.resolve(
                    dispatch({
                        type: 'STUDENT_ADD_ERROR',
                        error: 'Intentional Error Message'
                    })
                );
            }
        }, 1000);
    };
};

Позволит вам связать setState и закрыть модальное сразу после сохранения предмета:

handleAddNew = () => {
    let item = this.state.dataItem;
    item['id'] = uuid.v4();
    this.props.dispatch(addStudentAction(item)).then(() => {
        console.log('boom');
        this.setState({ add: false });
    });
};

Обратите внимание, что для этого вам нужно будет явно использовать dispatch в своих действиях для каждого действия вместо использования mapDispatchToProps.

Я изменил codesandbox , чтобы вы могли проверить желаемое поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...