反应正确的方法来刷新表数据

时间:2020-01-02 16:50:18

标签: javascript reactjs react-redux

我有一个返回两个组件的容器-一个用于添加新旅程的表单和一个用于列出所有旅程的表格。表单和表格都在同一页面上。

在表格中,我要添加一个可点击的单元格以编辑/删除旅程。虽然我可以删除给定的旅程,但是在尝试渲染表时,页面会在之后立即中断,因为其中一种旅程不再存在。

实现此功能的最佳方法是什么,当数据发生变化时,我可以从同一页面添加/编辑/删除旅程并用更新的数据刷新表?

journeysAdmin容器:

class JourneysAdmin extends Component {
  componentDidMount() {
    this.props.onFetchJourneys(this.props.token, this.props.userId);
  }

  renderTableHeader() {
    return (
      <TableHead>
        <TableRow>
          <TableCell>ID</TableCell>
          <TableCell>Name</TableCell>
          <TableCell>Description</TableCell>
          <TableCell>Progress</TableCell>
          <TableCell>Journey Points</TableCell>
          <TableCell>Journey Status</TableCell>
        </TableRow>
      </TableHead>
    );
  }

  render() {
    let journeys = <Spinner />;
    if (!this.props.loading) {
      journeys = this.props.journeys.map(journey => (
        <JourneyAdmin
          key={journey._id}
          journeyID={journey._id}
          name={journey.name}
          description={journey.description}
          progress={journey.journeyPoints}
          journeyPoints={journey.journeyPoints}
          journeyStatus={journey.status}
          journeyUserType={journey.journeyUserType}
          isAuthenticated={this.props.user.isAuthenticated}
          role={this.props.user.role}
          lessons={journey.lessons}
          journeyClicked={() =>
            this.props.onJourneyClicked(
              this.props.token,
              journey._id,
              this.props.userId
            )
          }
          deleteJourney={() =>
            this.props.onJourneyDeleted(journey._id, this.props.token)
          }
        />
      ));
    }
    return (
      <Paper>
        <JourneyAdminForm
          createjourney={(
            journeyName,
            journeyDescription,
            journeyPoints,
            journeyLevel,
            journeyTime,
            lessonName,
            lessonShortDescription,
            lessonDescription,
            lessonExampleText
          ) =>
            this.props.onAddJourney(
              journeyName,
              journeyDescription,
              journeyPoints,
              journeyLevel,
              journeyTime,
              lessonName,
              lessonShortDescription,
              lessonDescription,
              lessonExampleText,
              this.props.token
            )
          }
        />
        <Table>
          {this.renderTableHeader()}
          {journeys}
        </Table>
      </Paper>
    );
  }
}

const mapStateToProps = state => {
  return {
    journeys: state.journey.journeys,
    loading: state.journey.loading,
    token: state.auth.token,
    userId: state.auth.userId,
    user: state.auth
  };
};

const mapDispatchToProps = dispatch => {
  return {
    onFetchJourneys: (token, userId) =>
      dispatch(actions.fetchJourneys(token, userId)),
    onJourneyDeleted: (journeyID, token) =>
      dispatch(actions.deleteJourney(journeyID, token)),
    onAddJourney: (
      journeyName,
      journeyDescription,
      journeyPoints,
      journeyLevel,
      journeyTime,
      lessonName,
      lessonShortDescription,
      lessonDescription,
      lessonExampleText,
      token
    ) =>
      dispatch(
        actions.addJourney(
          journeyName,
          journeyDescription,
          journeyPoints,
          journeyLevel,
          journeyTime,
          lessonName,
          lessonShortDescription,
          lessonDescription,
          lessonExampleText,
          token
        )
      )
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withErrorHandler(JourneysAdmin, axios));

journeysAdmin表单组件:

class JourneyAdminForm extends Component {
  state = {
    controls: {
      Name: {
        elementType: "input",
        elementConfig: {
          placeholder: "Name"
        },
        value: "",
        validation: {
          required: true,
          minLength: 8
        },
        valid: false,
        touched: false
      },
      Description: {
        elementType: "input",
        elementConfig: {
          placeholder: "Description"
        },
        value: "",
        validation: {
          required: true,
          minLength: 8
        },
        valid: false,
        touched: false
      },
      Points: {
        elementType: "input",
        elementConfig: {
          placeholder: "Points"
        },
        value: "",
        validation: {
          required: true,
          min: 100,
          max: 999,
          isNumeric: true
        },
        valid: false,
        touched: false
      },
      Level: {
        elementType: "input",
        elementConfig: {
          placeholder: "Level"
        },
        value: "",
        validation: {
          required: true,
          minLength: 1
        },
        valid: false,
        touched: false
      },
      journeyTime: {
        elementType: "input",
        elementConfig: {
          placeholder: "Journey time"
        },
        value: "",
        validation: {
          minLength: 2,
          isNumeric: true
        },
        valid: false,
        touched: false
      },
      lessonName: {
        elementType: "input",
        elementConfig: {
          placeholder: "Lesson Name"
        },
        value: "",
        validation: {
          required: true,
          minLength: 8
        },
        valid: false,
        touched: false
      },
      lessonShortDescription: {
        elementType: "input",
        elementConfig: {
          placeholder: "Lesson short-description"
        },
        value: "",
        validation: {
          required: true,
          minLength: 8
        },
        valid: false,
        touched: false
      },
      lessonDescription: {
        elementType: "input",
        elementConfig: {
          placeholder: "Lesson description"
        },
        value: "",
        validation: {
          required: true,
          minLength: 8
        },
        valid: false,
        touched: false
      },
      lessonExampleText: {
        elementType: "input",
        elementConfig: {
          placeholder: "Lesson example text"
        },
        value: "",
        validation: {
          required: true,
          minLength: 8
        },
        valid: false,
        touched: false
      }
    }
  };

  checkValidity(value, rules) {
    let isValid = true;
    if (!rules) {
      return true;
    }

    if (rules.required) {
      isValid = value.trim() !== "" && isValid;
    }

    if (rules.minLength) {
      isValid = value.length >= rules.minLength && isValid;
    }

    if (rules.maxLength) {
      isValid = value.length <= rules.maxLength && isValid;
    }

    if (rules.isEmail) {
      const pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
      isValid = pattern.test(value) && isValid;
    }

    if (rules.isNumeric) {
      const pattern = /^\d+$/;
      isValid = pattern.test(value) && isValid;
    }

    return isValid;
  }

  inputChangedHandler = (event, controlName) => {
    let updatedControls = {
      ...this.state.controls,
      [controlName]: {
        ...this.state.controls[controlName],
        value: event.target.value,
        valid: this.checkValidity(
          event.target.value,
          this.state.controls[controlName].validation
        ),
        touched: true
      }
    };
    this.setState({ controls: updatedControls });
  };

  submitHandler = event => {
    event.preventDefault();
    console.log("Create button on JourneyAdmin page was clicked");
    this.props.createjourney(
      this.state.controls.Name.value,
      this.state.controls.Description.value,
      this.state.controls.Points.value,
      this.state.controls.Level.value,
      this.state.controls.journeyTime.value,
      this.state.controls.lessonName.value,
      this.state.controls.lessonShortDescription.value,
      this.state.controls.lessonDescription.value,
      this.state.controls.lessonExampleText.value
    );
  };

  render() {
    const formElementsArray = [];

    for (let key in this.state.controls) {
      formElementsArray.push({
        id: key,
        config: this.state.controls[key]
      });
    }

    let form = null;
    form = formElementsArray.map(formElement => (
      <Input
        key={formElement.id}
        elementType={formElement.config.elementType}
        elementConfig={formElement.config.elementConfig}
        value={formElement.config.value}
        invalid={!formElement.config.valid}
        shouldValidate={formElement.config.validation}
        touched={formElement.config.touched}
        changed={event => this.inputChangedHandler(event, formElement.id)}
      />
    ));

    if (this.props.loading) {
      form = <Spinner />;
    }

    let errorMessage = null;

    if (this.props.status === "fail") {
      errorMessage = <p>Journey could not be added because of errors!</p>;
    } else if (this.props.status === "success") {
      errorMessage = <p>New Journey has been created!!</p>;
    }

    return (
      <div>
        <form onSubmit={this.submitHandler}>
          {form}
          <button btnType="Success">Create</button>
        </form>
        {errorMessage}
      </div>
    );
  }
}

export default JourneyAdminForm;

JourneysAdmin表组件:

class JourneyAdmin extends Component {

  handleEditClick = (id, column) => {
    return event => {
      console.log(`You will Edit row with id ${id}, Name: ${column}.`);
    };
  };

  handleDeleteClick = (id, column) => {
    return event => {
      console.log(`You will delete on row with id ${id}, Name: ${column}.`);
      this.props.deleteJourney(this.props.journeyID);
    };
  };

  render() {
    return (
      <Aux>
        <TableBody>
          <TableRow key={this.props.journeyID}>
            <TableCell>{this.props.journeyID}</TableCell>
            <TableCell>{this.props.name}</TableCell>
            <TableCell>{this.props.description}</TableCell>
            <TableCell>{this.props.progress}</TableCell>
            <TableCell>{this.props.journeyPoints}</TableCell>
            <TableCell>{this.props.journeyStatus}</TableCell>
            <TableCell
              onClick={this.handleEditClick(
                this.props.journeyID,
                this.props.name
              )}
            >
              EDIT
            </TableCell>
            <TableCell
              onClick={this.handleDeleteClick(
                this.props.journeyID,
                this.props.name
              )}
            >
              Delete
            </TableCell>
          </TableRow>
        </TableBody>
      </Aux>
    );
  }
}

export default JourneyAdmin;

1 个答案:

答案 0 :(得分:0)

最后找到了问题。这不是在我的动作/减速器中正确添加/删除旅程。每次我向数据库添加旅程时,我都没有将它添加到状态中的journeys对象,也没有从数据库中再次获取旅程以使更新后的列表进入状态。

类似地,在删除时,我执行完删除操作后并未获取旅程。因此状态未更新。

现在我正在做所有动作:

axios
      .post(journeyjurl, newJourney)
      .then(res => {
        const addedJourney = [];
        for (let key in res) {
          addedJourney.push({
            ...res.data[key],
            id: key
          });
        }
        dispatch(addJourneySuccess(addedJourney[0].data));
      })

在减速器中:

const addJourneysSuccess = (state, action) => {
  return updateObject(state, {
    journeys: state.journeys.concat(action.addedjourney),
    loading: false
  });
};

在“删除”操作中:

  axios
      .delete(journeyjurl)
      .then(res => {
        dispatch(deleteJourneySuccess());
        dispatch(fetchJourneys(token, ""));
      })

我还发现,从我要在其中调用添加/删除操作的容器/组件(例如:在fetchJourneys中)调用handleDeleteClick也是可以的。因此,在我上面的评论中,基本上是1和3。

希望这对以后像我这样的菜鸟有帮助!