尝试使用.strike()剔除React中的Li元素

时间:2019-05-20 21:53:25

标签: reactjs

我正在尝试使用从DisplayTasks组件返回的索引来访问DOM中的列表字符串(从我的控制台日志中看起来很成功),然后在单击时删除该字符串。问题是,尽管console.log告诉我它在其周围放置了罢工标签,但实际上并没有在点击时删除字符串。不知道为什么吗?

App.js中的

strikeTask方法

 strikeTask = index => {
    const string = document.getElementById(index).childNodes[1].data
    string.strike()
  }


显示任务组件:

import React from 'react';

const DisplayTasks = ({ tasks, removeTask, strikeTask }) => { 
  return (
    <ol> 
      {tasks.map((task, index) => 
        <li key={index} id={index} onClick={() => strikeTask(index) }> {task} 
        <button style={{ marginLeft: '10px' }} onClick={() => removeTask(index) }>Remove</button>
        </li>)}
    </ol>
    )
}

export default DisplayTasks;

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>

<script type="text/babel">

/* InputTaskForm renders a form, and returns the input to our storeTask method. */
const InputTaskForm = ({ task }) => {
  return (
    <form name="charlie" onSubmit={task}>
      <input name="userinput" type="text" />
      <button type="submit">Submit</button>
    </form>
  );
};

const DisplayTasks = ({ tasks, removeTask, strikeTask }) => {
  return (
    <ol>
      {tasks.map((task, index) => (
        <li key={index} id={index} onClick={() => strikeTask(index)}>
          {" "}
          {task}
          <button
            style={{ marginLeft: "10px" }}
            onClick={() => removeTask(index)}
          >
            Remove
          </button>
        </li>
      ))}
    </ol>
  );
};

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      userinput: "",
      tasksarray: []
    };
  }

  /* =================================================================================
                                        #METHODS 
   ================================================================================= */

  /* ================================== #STORE TASK ================================== 
    - event.preventDefault(); stops the form from refreshing
    - The setState function updates our states via user input returned from the InputTaskForm 
         component
    - document.forms['charlie'].reset() resets the form after the user submits a task.
   ============================================================================= */
  storeTask = event => {
    event.preventDefault();
    this.setState({
      userinput: event.target.userinput.value,
      tasksarray: this.state.tasksarray.concat(
        " " + event.target.userinput.value
      )
    });
    document.forms["charlie"].reset();
  };

  /* ================================== #REMOVE TASK ================================== 
    - use the spread operator to copy the state of our tasksarray into a new array.
    - use the index returned from our onClick event to identify which item to remove.
    - remove the item from our new array via splice then replace our old array using setState.
   ============================================================================= */
  removeTask = index => {
    const removedTasksArray = [...this.state.tasksarray];
    removedTasksArray.splice(index, 1);
    this.setState({ tasksarray: removedTasksArray });
  };

  /* ============================== #CROSS OUT TASK ============================== 
   ============================================================================= */
  strikeTask = index => {
    const string = document.getElementById(index).childNodes[1].data;
    string.strike();
  };

  /* ================================ #COMPONENTS  ================================ 
  - const { tasksarray } = this.state  is to destructure tasksarray (so we 
     no longer have to prefix this.state to it when we want to use it)
  - InputTaskForm renders a form, and returns the input to our storeTask method.
  - DisplayTasks maps each input in the tasksarray state into an html list.
   ============================================================================= */
  render() {
    const { tasksarray } = this.state;
    return (
      <div>
        <InputTaskForm task={this.storeTask} />
        <DisplayTasks
          tasks={tasksarray}
          removeTask={this.removeTask}
          strikeTask={this.strikeTask}
        />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
</script>

2 个答案:

答案 0 :(得分:1)

发生问题是因为string.strike()返回了您想要的字符串,但是它没有用新值修改dom。您可以:

  1. 直接修改dom:
strikeTask = index => {
  const string = document.getElementById(index).childNodes[1].data
  document.getElementById(index).innerHTML = string.strike()
}
  1. 创建一个处理其自身stricken状态的组件并相应地管理您的CSS(类,js中的CSS,无论您使用什么)。
const Task = ({ task, removeTask, index }) => {
  const [isStricken, setIsStricken] = useState(false)
  return (
    <li
      onClick={() => setIsStricken(true)}
      className={isStricken ? 'stricken' : ''}
    >
      {task} 
      <button
        style={{ marginLeft: '10px' }}
        onClick={() => removeTask(index) }
      >
        Remove
      </button>
    </li>
  )
}

这是一种更具声明性的方法(React鼓励这样做),因为您的组件正在对状态更改做出反应,而不是手动修改dom。

答案 1 :(得分:1)

将任务另存为[{ title: 'some title', strike: false }]之类的对象,然后单击标题设置为true的标题。不要修改dom元素,直接使用状态来管理dom。

选项1:

storeTask = event => {

event.preventDefault();
  this.setState({
    userinput: event.target.userinput.value,
    tasksarray: [
      ...this.state.tasksarray,
      { title: event.target.userinput.value, strike: false }
    ]
  });
  document.forms["charlie"].reset();
};

罢工任务功能,将罢工属性设置为true |错误。

strikeTask = index => {
  const selected = this.state.tasksarray[index];

  this.setState({
    tasksarray: [
      ...this.state.tasksarray.slice(0, index),
      Object.assign({}, this.state.tasksarray[index], {
        title: selected.title,
        strike: !selected.strike
      }),
      ...this.state.tasksarray.slice(index + 1)
    ]
  });
};

在显示任务组件中,检查strike是否为true。如果是带有<strike>标签的环绕文字

const DisplayTasks = ({ tasks, removeTask, strikeTask }) => {
  return (
    <ol>
      {tasks.map((task, index) => (
        <li key={index} id={index} onClick={() => strikeTask(index)}>
          {" "}
          {task.strike ? <strike>{task.title}</strike> : task.title}
          <button
            style={{ marginLeft: "10px" }}
            onClick={e => removeTask(e, index)}
          >
            Remove
          </button>
        </li>
      ))}
    </ol>
  );
};

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>

<script type="text/babel">

const InputTaskForm = ({ task }) => {
  return (
    <form name="charlie" onSubmit={task}>
      <input name="userinput" type="text" />
      <button type="submit">Submit</button>
    </form>
  );
};

const DisplayTasks = ({ tasks, removeTask, strikeTask }) => {
  return (
    <ol>
      {tasks.map((task, index) => (
        <li key={index} id={index} onClick={() => strikeTask(index)}>
          {" "}
          {task.strike ? <strike>{task.title}</strike> : task.title}
          <button
            style={{ marginLeft: "10px" }}
            onClick={e => removeTask(e, index)}
          >
            Remove
          </button>
        </li>
      ))}
    </ol>
  );
};

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      userinput: "",
      tasksarray: []
    };
  }

  /* =================================================================================
                                      #METHODS 
   ================================================================================= */

  /* ================================== #STORE TASK ================================== 
    - event.preventDefault(); stops the form from refreshing
    - The setState function updates our states via user input returned from the InputTaskForm 
         component
    - document.forms['charlie'].reset() resets the form after the user submits a task.
   ============================================================================= */
  storeTask = event => {
    event.preventDefault();
    this.setState({
      userinput: event.target.userinput.value,
      tasksarray: [
        ...this.state.tasksarray,
        { title: event.target.userinput.value, strike: false }
      ]
    });
    document.forms["charlie"].reset();
  };

  /* ================================== #REMOVE TASK ================================== 
    - use the spread operator to copy the state of our tasksarray into a new array.
    - use the index returned from our onClick event to identify which item to remove.
    - remove the item from our new array via splice then replace our old array using setState.
   ============================================================================= */
  removeTask = (e, index) => {
    e.stopPropagation();
    const removedTasksArray = [...this.state.tasksarray];
    removedTasksArray.splice(index, 1);
    this.setState({ tasksarray: removedTasksArray });
  };

  /* ============================== #CROSS OUT TASK ============================== 
   ============================================================================= */
  strikeTask = index => {
    const selected = this.state.tasksarray[index];

    this.setState({
      tasksarray: [
        ...this.state.tasksarray.slice(0, index),
        Object.assign({}, this.state.tasksarray[index], {
          title: selected.title,
          strike: !selected.strike
        }),
        ...this.state.tasksarray.slice(index + 1)
      ]
    });
  };

  // strikeTask = index => {
  //   var x = document.getElementById(index);
  //   if (x.style.display === "none") {
  //     x.style.display = "block";
  //   } else {
  //     x.style.display = "none";
  //   }
  // }

  /* ================================ #COMPONENTS  ================================ 
  - const { tasksarray } = this.state  is to destructure tasksarray (so we 
     no longer have to prefix this.state to it when we want to use it)
  - InputTaskForm renders a form, and returns the input to our storeTask method.
  - DisplayTasks maps each input in the tasksarray state into an html list.
   ============================================================================= */
  render() {
    const { tasksarray } = this.state;
    return (
      <div>
        <InputTaskForm task={this.storeTask} />
        <DisplayTasks
          tasks={tasksarray}
          removeTask={this.removeTask}
          strikeTask={this.strikeTask}
        />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
</script>

选项2:

创建一个TodoItem组件,每个组件通过行为来管理罢工。

class TodoItem extends React.Component {
  state = {
    strike: false
  }

  strikeTask = () => {
    this.setState({
      strike: !this.state.strike
    })
  }

  render() {
    const { strike } = this.state;
    return (
      <li onClick={this.strikeTask}>
        {" "}
        {strike ? <strike>{this.props.text}</strike> : this.props.text}
        <button
          style={{ marginLeft: "10px" }}
          onClick={this.props.removeTask}
        >
          Remove
          </button>
      </li>
    )
  }
}

然后使用它

const DisplayTasks = ({ tasks, removeTask, strikeTask }) => {
  return (
    <ol>
      {tasks.map((task, index) => (
      <TodoItem text={task} removeTask={() => removeTask(index)} />
      ))}
    </ol>
  );
};

        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
        <div id="root"></div>

     <script type="text/babel">
        
    class TodoItem extends React.Component {
      state = {
        strike: false
      }

      strikeTask = () => {
        this.setState({
          strike: !this.state.strike
        })
      }

      render() {
        const { strike } = this.state;
        return (
          <li onClick={this.strikeTask}>
            {" "}
            {strike ? <strike>{this.props.text}</strike> : this.props.text}
            <button
              style={{ marginLeft: "10px" }}
              onClick={this.props.removeTask}
            >
              Remove
              </button>
          </li>
        )
      }
    }

        /* InputTaskForm renders a form, and returns the input to our storeTask method. */
        const InputTaskForm = ({ task }) => {
          return (
            <form name="charlie" onSubmit={task}>
              <input name="userinput" type="text" />
              <button type="submit">Submit</button>
            </form>
          );
        };

        const DisplayTasks = ({ tasks, removeTask, strikeTask }) => {
          return (
            <ol>
              {tasks.map((task, index) => (
               <TodoItem text={task} removeTask={() => removeTask(index)} />
              ))}
            </ol>
          );
        };

        class App extends React.Component {
          constructor() {
            super();
            this.state = {
              userinput: "",
              tasksarray: []
            };
          }

          /* =================================================================================
                                                #METHODS 
           ================================================================================= */

          /* ================================== #STORE TASK ================================== 
            - event.preventDefault(); stops the form from refreshing
            - The setState function updates our states via user input returned from the InputTaskForm 
                 component
            - document.forms['charlie'].reset() resets the form after the user submits a task.
           ============================================================================= */
          storeTask = event => {
            event.preventDefault();
            this.setState({
              userinput: event.target.userinput.value,
              tasksarray: this.state.tasksarray.concat(
                " " + event.target.userinput.value
              )
            });
            document.forms["charlie"].reset();
          };

          /* ================================== #REMOVE TASK ================================== 
            - use the spread operator to copy the state of our tasksarray into a new array.
            - use the index returned from our onClick event to identify which item to remove.
            - remove the item from our new array via splice then replace our old array using setState.
           ============================================================================= */
          removeTask = index => {
            const removedTasksArray = [...this.state.tasksarray];
            removedTasksArray.splice(index, 1);
            this.setState({ tasksarray: removedTasksArray });
          };

          /* ============================== #CROSS OUT TASK ============================== 
           ============================================================================= */
          strikeTask = index => {
            const string = document.getElementById(index).childNodes[1].data;
            string.strike();
          };

          /* ================================ #COMPONENTS  ================================ 
          - const { tasksarray } = this.state  is to destructure tasksarray (so we 
             no longer have to prefix this.state to it when we want to use it)
          - InputTaskForm renders a form, and returns the input to our storeTask method.
          - DisplayTasks maps each input in the tasksarray state into an html list.
           ============================================================================= */
          render() {
            const { tasksarray } = this.state;
            return (
              <div>
                <InputTaskForm task={this.storeTask} />
                <DisplayTasks
                  tasks={tasksarray}
                  removeTask={this.removeTask}
                  strikeTask={this.strikeTask}
                />
              </div>
            );
          }
        }

        ReactDOM.render(<App />, document.getElementById("root"));
        </script>