React将状态传递给兄弟组件,直到父类

时间:2017-06-28 01:41:27

标签: reactjs state

React非常新,我似乎陷入困境。这是一个简单的Todo应用程序,我基本上有3个组件,基本组件,输入组件和任务组件。我已经弄清楚如何编辑每个组件中的状态,但是我无法将状态从组件传递到组件。

class App extends Component {
    render() {
        return (
            <div id="appContainer">
                <HeaderTitle />
                <TaskInput />
                <Task taskState={true} text="task one" />
                <Task taskState={true} text="task two" />
                <Task taskState={true} text="task three" />
            </div>
        );
    }

}

class TaskInput extends React.Component {
    constructor(props) {
        super(props);
        this.state = {}
    }
    update(e) {
        this.setState({inputValue: e.target.value});
        console.log(this.state);
    }
    taskCreate(e) {
        this.setState({text: this.state.inputValue, completeState: false});
        console.log('button clicked');
        console.log(this.state);
    }
    render () {
        return (
            <div className="taskInputContainer">
                <TaskInputField update={this.update.bind(this)} taskCreate={this.taskCreate.bind(this)} />
            </div>
        )
    }
}


class Task extends Component {
    constructor(props) {
        super();
        this.state = {
            completeState: false
        }
    }
    toggleTask (e) {
        this.setState({
            completeState: !this.state.completeState
        });
    }
    delete (item) {

    }
    render() {
        return (
            <div className="taskContainer" onClick={this.toggleTask.bind(this)}>
                <div className={"taskState " + this.state.completeState}></div>
                <div className={"taskText " + this.state.completeState }>{this.props.text}</div>
                <div className="taskDelete"><i className="fa fa-times-circle-o" aria-hidden="true"></i></div>
            </div>
        );
    }
}

const TaskInputField = (props) =>
    <div className="taskInputContainer">
        <input type="text" className="taskInputField" onChange={props.update}/>
        <i className="fa fa-plus-circle" aria-hidden="true" onClick={props.taskCreate}></i>
    </div>;

Task.propTypes = {
    text: PropTypes.string.isRequired,
    completeState: PropTypes.bool
};
Task.defaultProps = {
    text: 'Task',
    completeState: false
};

const HeaderTitle = () => (
    <h1>Davids Todo List</h1>
);

export default App;

所以在TaskInput中有自己的状态我可以更新但是如何将其传递给父组件以更新和添加Task组件?另外如何在不重新渲染整个任务的情况下添加Task组件?

1 个答案:

答案 0 :(得分:2)

在React documentation中的“解除状态”一文中详细记录了这个问题。

TLDR,您创建一个处理程序,用于更新当前组件的状态并将其作为props传递给子组件。在下面的示例中(代码的修改版本),我将用于更改组件App状态的方法传递给其子组件(TaskInput和Tasks)。

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      tasks: [],
    }
  }
    
  addTask = (e, text) => {
    e.preventDefault();
    const newTask = {
      id: new Date().getTime(),
      done: false,
      text
    };
    const newTasks = this.state.tasks.concat([newTask]);
    this.setState({
      tasks: newTasks
    })
  }
    
  toggleTask = (id) => {
    const updatedTask = this.state.tasks.filter(task => task.id === id);
    updatedTask[0].done = !updatedTask[0].done;
    const newTasks = this.state.tasks.map(task => {
      if (task.id === id) {
        return updatedTask[0];
      }
      return task;
    });
    this.setState({
      tasks: newTasks
    });
  }
    
  render() {
    return (
      <div id="appContainer">
        <HeaderTitle />
        <TaskInput addTask={this.addTask} />
        {
          this.state.tasks.length > 0 ? <Tasks tasks={this.state.tasks} toggleTask={this.toggleTask}/> : <div>no tasks yet</div>
        }
      </div>
    );
  }

}

class TaskInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentInput: ''
    }
  }
  
  handleChangeText = (e) => {
    this.setState({
      currentInput: e.target.value,
    })
  }
  
  render() {
    return (<form>
<input type="text" value={this.state.currenInput} onChange={this.handleChangeText}/><input type="submit" onClick={(e) => this.props.addTask(e, this.state.currentInput)} value="Add Task"/></form>)
  }
} 


const Tasks = (props) => (
  <div>
    {
      props.tasks.map(task => (
        <div 
          style={ task.done ? { textDecoration: 'line-through'} : {} }
          onClick={() => props.toggleTask(task.id)}
          >{task.text}</div>
      ))
    }
  </div>
);

const HeaderTitle = () => (
  <h1>Davids Todo List</h1>
);

ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>