我如何在 React 中触发几个组件更高的功能?

How do I trigger a function several components higher in React?

刚学React,想在font awesome icon上加个onClick,运行加个markTaskAsCompleted功能。我遇到了麻烦,因为它是层次结构中较低的几个组件。你会如何理想地去做这件事?请记住,我还必须在函数中传递任务的 ID。

class TasksBase extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      loading: false,
      tasks: [],
    };
  }

  componentDidMount() {
    this.onListenForTasks();
  }

  onListenForTasks() {
    this.setState({ loading: true });
    this.unsubscribe = this.props.firebase
      .tasks()
      .orderBy('created', 'desc')
      .onSnapshot(snapshot => {
        if (snapshot.size) {
          let tasks = [];
          snapshot.forEach(doc =>
            tasks.push({ ...doc.data(), uid: doc.id }),
          );
          this.setState({
            tasks: tasks,
            loading: false
          });
        } else {
          this.setState({ tasks: null, loading: false });
        }
    });
  }

  markTaskAsCompleted(){
    console.log("Completed");
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  render() {
    const { tasks, loading } = this.state;
    return (
      <div>
        {loading && <div>Loading ...</div>}
        {tasks ? (
          <TaskList tasks={tasks} />
        ):(
          <div>There are no tasks ...</div>
        )}
      </div>
    );
  }

}


const Tasks = withFirebase(TasksBase);

const TaskList = ({ tasks }) => (
  <ul className="tasks">
    {tasks.map( task => (
      <Task key={task.uid} task={task} />
    ))}
  </ul>
);

const Task = ({ task }) => (
  (!task.completed && !task.obsolete && !task.waitingForDependencies) &&
  <li className="task">
    <strong>{task.userId}</strong> {task.name}
    <div className="icons">
      <FontAwesomeIcon icon="check-circle"/>
      <FontAwesomeIcon icon="times-circle" />
    </div>
  </li>
);

const condition = authUser => !!authUser;

export default compose(
  withEmailVerification,
  withAuthorization(condition),
)(Tasks);

您需要将其作为

传递到树下

markTaskAsCompleted={this.props.markTaskAsCompleted}

并确保该函数在构造函数中绑定到父级。

您可以使用 refs 或 document.getElementById 获取 ID。

在构造函数中绑定您的 class 函数:

this.markTaskAsCompleted = this.markTaskAsCompleted.bind(this);

使用 props 将函数传递到子组件中:

<TaskList tasks={tasks} handleMarkCompleted={this.markTaskAsCompleted} />

再次将函数传递给子组件,这是 prop drilling,不是最新最好的方法,但它有效:

const TaskList = ({ tasks, handleMarkCompleted }) => (
  <ul className="tasks">
    {tasks.map( task => (
      <Task key={task.uid} task={task} handleMarkCompleted={handleMarkCompleted} />
    ))}
  </ul>
);

触发函数onClick:

inside <Task>...
<FontAwesomeIcon icon="check-circle" onClick={() => handleMarkCompleted(task.uid)} />

如果将数据传递到函数中(例如 task.uid),请在函数定义中也将其作为参数,以便您可以使用它:

markTaskAsCompleted(id){
    console.log("Completed", id);
}