react.js删除少数渲染组件之一

时间:2017-10-23 18:25:26

标签: javascript reactjs dom

这是我的第一篇文章。 我正在创建todo应用程序。 当点击加号按钮时,我的应用程序正在向任务列表中添加新任务,并且在几次点击之后你得到的任务很简单,但问题是每个任务都有删除图标,遗憾的是由于我缺乏足够的技能而删除了所有组件而不是一个,哪个图标属于。

这是App.js代码

class App extends React.Component {
constructor(props){
    super(props);
    this.handleDelete = this.handleDelete.bind(this);
    this.addTask = this.addTask.bind(this);
    this.state = {taskNum: 0,
                  delete: false            
    }
}
addTask(){
    this.setState({
        taskNum: this.state.taskNum +1,
        delete:false
    });
}
handleDelete(e){
    console.log(e.target);
    this.setState({delete: true});
}
render() {
    const tasks = [];
    for (let i = 0; i < this.state.taskNum; i += 1) {
        tasks.push(!this.state.delete && <Task key={i} number={i} deleteTask={this.handleDelete}/>);
      };

  return (
    <div className="ui container content">
        <h2 className="centerHeader header">TODO LIST</h2>
        <h3 className="taskheader secondaryHeader">Tasks <Icon className="addNew plus" action={this.addTask}/></h3>
        <div className="ui container five column grid taskList">
            {tasks}
        </div> ...

这里是Task.js

export class Task extends React.Component {
  constructor(props){
    super(props);
    this.dataChanged = this.dataChanged.bind(this);
    this.state ={message: 'TASK' + (this.props.number+1),
                }
    }
    customValidateText(text) {
      return (text.length > 0 && text.length < 31);
    }
    dataChanged(data) {
      console.log(data.message);
       this.setState({message: data.message});
    }
    render(){
    const centerRow = classNames('textCenter', 'row');
    return (<div className="ui column task">
                  <div className={centerRow}><InlineEdit
              validate={this.customValidateText}
              activeClassName="editing"
              text={this.state.message}
              paramName="message"
              change={this.dataChanged}
              style={{
                background: 'inherit',
                textAlign:'center',
                maxWidth: '100%' ,
                display: 'inline-block',
                margin: 0,
                padding: 0,
                fontSize: '1em',
                outline: 0,
                border: 0
              }}
            /></div>
                  <div className={centerRow}><Icon className="browser outline huge center"/> </div>
                  <div className={centerRow}><Icon className="large maximize"/><Icon className="large save saveTask"/><Icon className="large trash outline" action={this.props.deleteTask} /></div>
          </div>
          );

我想过尝试e.target并选择parentNode但我不确定这是否是正确的解决方案,因为使用react,所以你可以帮我找到这个问题的有效解决方案,这样当点击垃圾图标时它会删除只有父组件。

1 个答案:

答案 0 :(得分:0)

反应强大的一个主要原因是,它使您能够根据您的数据维护DOM,而无需自己对DOM进行任何操作

因此,为了让你的例子更加友好,你需要做一些改变,这也将解决你的问题

1-您需要保持数据的实际状态,因此添加待办事项表示添加到程序中的实际实际数据,而不仅仅是组件表示。

2-删除由component表示的任务意味着删除它自己的数据,因此删除其中一个任务意味着删除其实际数据,然后反应将处理为您更新DOM,所以想法隐藏组件的标志不是React JS方式

3-反应方式知道何时呈现以及如何处理所有数据由组件state管理..因此您将数据保存在组件state中,您只需要关心更新state,然后反应将知道它将需要再次渲染,但现在使用新的更新任务列表



我在代码中做了一些更改,并用注释行解释原因

class App extends React.Component {
    constructor(props){
        super(props);
        this.handleDelete = this.handleDelete.bind(this);
        this.addTask = this.addTask.bind(this);
        this.state = {
                tasks: [  ], // this is the array that will hold the actual data and based on its content react will handle rendering the correct data
                counter : 1  // this counter is incremented every task addition just to make sure we are adding different task name just for the example explanation
            }
        }
    }

    addTask(){
        this.setState({
            tasks: this.state.tasks.push( "TASK" + counter); //This how we add a new task as i said you are adding an actual task data to the state
            counter : this.state.counter + 1 //increment counter to have different task name for the next addition
        });
    }

    //i changed this function to accept the task name so when you click delete it will call this function with task name as parameter
    //then we use this task name to actually remove it from the tasks list data in our state
    handleDelete(taskToDelete){

        this.setState({
            //the filter function below will remove the task from the array in our state
            //After this state update, react will render the component again but now with the tasks list after removing deleting this one
            tasks : this.state.tasks.filter((task) => {
                if(task != taskToDelete)
                    return word;
            })
        });
    }

    render() {
        const tasks = [];
        //Notice here we pass an actual data to every Task component so i am adding prop message to take the value from this.state.tasks[index]
        for (let i=0 ; i< this.state.tasks.length ; i++)
        {
            tasks.push(<Task key={i} message={this.state.tasks[i]} deleteTask={this.handleDelete}/>);
        }


      return (
        <div className="ui container content">
            <h2 className="centerHeader header">TODO LIST</h2>
            <h3 className="taskheader secondaryHeader">Tasks <Icon className="addNew plus" action={this.addTask}/></h3>
            <div className="ui container five column grid taskList">
                {tasks}
            </div> ...
            )
    }
}

任务组件

export class Task extends React.Component {
    constructor(props){
        super(props);
        this.dataChanged = this.dataChanged.bind(this);
        this.removeCurrentTask = this.removeCurrentTask.bind(this);
        //Here i am setting the state from the passed prop message
        this.state ={
            message: this.props.message
        }
    }

    customValidateText(text) {
      return (text.length > 0 && text.length < 31);
    }

    dataChanged(data) {
       console.log(data.message);
       this.setState({message: data.message});
    }

    removeCurrentTask (){
        //calling the deleteTask function with the current task name.
        this.props.deleteTask(this.state.message);
    }

    render(){
        const centerRow = classNames('textCenter', 'row');
        return (
            <div className="ui column task">
                <div className={centerRow}><InlineEdit
                      validate={this.customValidateText}
                      activeClassName="editing"
                      text={this.state.message}
                      paramName="message"
                      change={this.dataChanged}
                      style={{
                        background: 'inherit',
                        textAlign:'center',
                        maxWidth: '100%' ,
                        display: 'inline-block',
                        margin: 0,
                        padding: 0,
                        fontSize: '1em',
                        outline: 0,
                        border: 0
                      }}
                    /></div>
                <div className={centerRow}><Icon className="browser outline huge center"/> </div>
                //Notice the action handler here is changed to use removeCurrentTask defined in current component 
                //BTW i don't know how Icon is handling the action property ... but now you can simply use onClick and call removeCurrentTask 
                <div className={centerRow}><Icon className="large maximize"/><Icon className="large save saveTask"/><Icon className="large trash outline" action={this.removeCurrentTask} /></div>
            </div>
              );
    }
}