简体   繁体   English

如何在React-Redux中更改状态时关闭模态对话框?

[英]How to close the Modal Dialog when state changed in React-Redux?

Basically, I want to change the UI state in the Component when the Global state has been changed in the Redux-Store. 基本上,我想在Redux-Store中更改Global状态时更改Component中的UI状态。

My scenario is as follow: 我的方案如下:

  1. Show the Modal Form when a user clicks a "Add Student" button 当用户单击“添加学生”按钮时显示模态表单
  2. Show "Saving..." when user clicks "Save" button 用户单击“保存”按钮时显示“正在保存...”
  3. If an error occurs, the dialog should stay open and show Error 如果发生错误,对话框应保持打开状态并显示错误
  4. If insertion is ok, the dialog should be closed automatically 如果插入正常,则应自动关闭对话框

在此输入图像描述

I have achieved the first 3 points, but I'm stuck at the 4th point and don't know how to implement the Close feature after the successful insertion. 我已经达到了前3分,但我在第4点陷入困境,并且在成功插入后不知道如何实现Close功能。

I would like to run the following example code whenever isSubmitting/error has been changed in the Redux-Store. 我想在Redux-Store中更改isSubmitting / error时运行以下示例代码。 But, I don't know where to run it. 但是,我不知道在哪里运行它。 I tried to put it in the render() method, but it doesn't work and I couldn't open the dialog anymore. 我试图将它放在render()方法中,但它不起作用,我无法打开对话框。

Code to Check and Close the Modal 检查和关闭模态的代码

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

I don't want to lift that UI state (Eg. IsModalOpen - bool) into the Global Redux store. 我不想将UI状态(例如IsModalOpen - bool)提升到Global Redux商店。 I have already put the UI state 'isSubmitting' into Redux and I don't want to keep adding UI states into the Redux Store. 我已经将UI状态'isSubmitting'放入Redux中,我不想继续将UI状态添加到Redux Store中。

Could you please suggest me how I can close the dialog after the successful insertion? 您能否建议我在成功插入后如何关闭对话框?

I put the sample code on the CodeSandbox and it's here 我把示例代码放在CodeSandbox上,就在这里

Reducer 减速器

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;

Container/Page 集装箱/页

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)
};

Modal Form 模态表格

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>
    );
  }
}

UPDATES 更新

It can be achieved by using componentDidUpdate lifecycle method as below: please be careful that you check the props and states correctly before deriving the state. 它可以通过使用componentDidUpdate生命周期方法来实现,如下所示:在导出状态之前,请注意检查道具和状态。

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

Or you can use getDerivedStateFromProps lifecycle method to re-calculate the props. 或者您可以使用getDerivedStateFromProps生命周期方法重新计算道具。 But I found it difficult to use than componentDidUpdate . 但我发现很难使用componentDidUpdate

It is bit more complex and clumsy to achieve that, but you can still force that behavior as follow: 实现这一点有点复杂和笨拙,但你仍然可以强制执行以下行为:

Using Promise on your action: 在行动中使用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);
    };
};

Will let you chain your setState and close the modal right after saving the item: 在保存项目后,可以让你链接你的setState并关闭模态:

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

Note that in order to do so, you will need to use dispatch on your actions explicitly for each action, instead of using mapDispatchToProps . 需要注意的是,为了做到这一点,你就需要使用dispatch明确你的行动的每一个动作,而不是使用mapDispatchToProps

I have modified the codesandbox so you can inspect the desired behavior. 我修改了代码框,以便您可以检查所需的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM