如何在 React 重定向之前等待事件处理程序的完成

How to await the completion of eventHandlers before redirect in React

我正在用 Redux-React-Realtime 数据库编写一个 Messenger 应用程序。在一个ProfileSearch页中,有很多MemberCard。我需要编写一个特定的功能,当我在个人资料页面上单击 MemberCard 上的“消息”按钮时,我将重定向到 Messenger 页面,并使用 channel_id 通过 props 传递给它,将加载与 message_room.

相关的所有属性

但是,我不确定如何使此交互同步。

目前,在调用消息按钮时,它会在我在 MemberCard 中的操作完全执行之前将我重定向到 Messenger 组件。是否有任何特定的方法来等待事件处理程序的完成,在事件处理程序的某些方法中获取 return 值并将该信息传递给另一个组件并在那里重定向?与其父组件 ProfileSearch.

不同,子组件 MemberCard 无法访问 this.props.history

这里有一个简短的片段来提供一些背景信息。

ProfileSearch.js

class ProfileSearch extends Component {



  constructor(props){
    super(props);
    this.state = {};
    const locals = this.state;
    locals[FILTERED_PROFILES] = [];
    //pass in searchUser
    locals["search"] = "";

  }



  renderProfiles = (profile) => {
    return (
      <MemberCard
        profile_id = {profile[PROFILE_ID]}
        display_name = {profile[PROFILE_PUBLIC_DISPLAY_NAME]}
      />)
  }


  onchange = e => {
    this.setState({ search: e.target.value });
  };

  render() {

    
    const { search } = this.state;
    const all_profiles = this.props[REDUX_DATA_ALL_PROFILES];
    const filtered_profiles = all_profiles.filter((profile) => {
      return profile[PROFILE_PUBLIC_DISPLAY_NAME].toLowerCase().indexOf(search.toLowerCase()) !== -1;
    });

    console.log("Printing filtered");
    console.log(filtered_profiles);

    return (
      <div className="flyout">
        <main style={{ marginTop: "4rem" }}>
          <div className="container">
            <div className="row">
              <div className="col">
                <Input
                  label="Search for profile display name"
                  icon="search"
                  onChange={this.onchange}
                />
              </div>
              <div className="col" />
            </div>
            <div className="profile-row">
              {filtered_profiles.map((profile) => {
                return this.renderProfiles(profile);
              })}
            </div>
          </div>
        </main>
      </div>
    );
  }
}

MemberCard.js

class MemberCard extends Component {
  //console.log(this.props) shows only user, profile_id and display_name
  handleSubmit = async (event) => {
    try {
      event.preventDefault();


      //some logic before calling the async function, which does firebase queries
      const channel_id = await select_or_create_message_room_method(channel);
      console.log(`Channel of uid ${channel_id} created`);
      //Passes channel_id to next component and redirect
    } catch (error) {
      console.log("Error with handleSubmit from MemberCard", error);
    }
  }



  render() {


    return (
      <Card className={"member"}>
        <CardActions>
          <Button size="small" color="secondary" onClick={this.handleSubmit} >
            <Link to={{
              pathname: APP_MESSENGER_PATH,
              state: {
                //Just testing out the features
                postalCode: 1,
                hasSubsidy: 2,
                subsidyType: 3,
                age: 4,
                nationality: 5
              }
            }}
            >
              <span style={{ color: "white" }}> Message { display_name } </span>
            </Link>
          </Button>
        </CardActions>
      </Card>
    );

  }
}

Messenger.js

class Messenger extends Component {


  //TODO: No need for PropTypes since it uses constructor pattern
  constructor(props) {

    super(props);
    this.state = {};
    const locals = this.state;
    locals[MESSENGER_ACTIVE_CHANNEL_ID] = this.props[MESSENGER_ACTIVE_CHANNEL_ID];//ideally gets the channel_id from the calling component
  }


  async componentDidMount() {

    console.log("Component did mount happen");


    if (this.state[MESSENGER_ACTIVE_CHANNEL_ID]) {
      //loads everything related to the active channel
    }


    console.log("Component did mount ended");
  }



  //TODO:most important, intercept here and change to Redux
  //console.log everything  here
  render() {
    //render items
  }
}

更新

我意识到我遗漏了一些会影响答案的信息。这是在某些子组件中发生的操作,因此 props.history 可能不会传递到那里。

只需删除 Link 并在 handleSubmit

末尾使用 history.push
handleSubmit = async (event) => {
  try {
    event.preventDefault();

    //some logic before calling the async function, which does firebase queries
    const channel_id = await select_or_create_message_room_method(channel);
    console.log(`Channel of uid ${channel_id} created`);
    //Passes channel_id to next component and redirect
    this.props.history.push({
      pathname: APP_MESSENGER_PATH,
      state: {
        //Just testing out the features
        postalCode: 1,
        hasSubsidy: 2,
        subsidyType: 3,
        age: 4,
        nationality: 5,
      },
    });
  } catch (error) {
    console.log("Error with handleSubmit from MemberCard", error);
  }
};

要读取 Messenger 组件中的数据,请执行以下操作:

this.props.location.state

编辑 根据评论...

您的 MemberCard 组件理想情况下应该可以访问历史对象,因为您正试图在那里使用 Link

无论如何...如果你想在MemberCard组件中访问历史记录,你有2个选项。

  1. MemberCard 个组件使用 withRouter
  2. 使用custom history object并将其传递给Router。这样您的 MemberCard 将可以访问历史对象。