我正在尝试使用从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>
答案 0 :(得分:1)
发生问题是因为string.strike()
返回了您想要的字符串,但是它没有用新值修改dom。您可以:
strikeTask = index => {
const string = document.getElementById(index).childNodes[1].data
document.getElementById(index).innerHTML = string.strike()
}
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>