Reactjs 组件需要两次单击来更新,而不是一次单击
我有一个按钮,可以将我的笔记存档并发送到单独的存档选项卡。我有以下设置,但是,当我点击归档后,它将需要一次点击,而点击取消归档后,将需要两次点击。我相信这是因为setstate是异步发生的,并且是在update调用之后发生的,但我不确定解决方案。我尝试过为存档之后调用的更新创建一个单独的函数,但没有成功。有什么想法吗 我还不能嵌入图像,所以这里是有问题的代码 完整的代码分解(目前是草率的) 此组件确定要通过道具传递给todolist的类别Reactjs 组件需要两次单击来更新,而不是一次单击,reactjs,event-handling,Reactjs,Event Handling,我有一个按钮,可以将我的笔记存档并发送到单独的存档选项卡。我有以下设置,但是,当我点击归档后,它将需要一次点击,而点击取消归档后,将需要两次点击。我相信这是因为setstate是异步发生的,并且是在update调用之后发生的,但我不确定解决方案。我尝试过为存档之后调用的更新创建一个单独的函数,但没有成功。有什么想法吗 我还不能嵌入图像,所以这里是有问题的代码 完整的代码分解(目前是草率的) 此组件确定要通过道具传递给todolist的类别 import React from 'react';
import React from 'react';
import TodoListContainer from './todo_list_container';
class Left extends React.Component {
constructor(props){
super(props);
this.state = {
category: "keeps"
}
this.activateKeeps = this.activateKeeps.bind(this);
this.activateArchive = this.activateArchive.bind(this);
this.activateTrash = this.activateTrash.bind(this);
}
activateKeeps(e){
e.preventDefault();
this.setState({ category: "keeps" })
}
activateArchive(e){
e.preventDefault();
this.setState({ category: "archive" })
}
activateTrash(e){
e.preventDefault();
this.setState({ category: "trash"})
}
render(){
let categ = this.state.category
return(
<div>
<div className="left-bar">
<div className="keeps" onClick={this.activateKeeps}>KEEPS</div>
<div className="archive" onClick={this.activateArchive}>ARCHIVE</div>
<div className="trashed" onClick={this.activateTrash}>TRASH</div>
</div>
<TodoListContainer category={categ} />
</div>
)
}
}
容器中的组件将基于通过componentWillReceiveProps中的道具向下推的类别进行渲染(我需要更改它的日期,但它似乎正在工作)
从“/todo_list_item”导入todolitem;
从“./todo_form”导入TodoForm;
从“/Preclick_form”导入预点击;
从“/Nav_container.jsx”导入导航;
类TodoList扩展了React.Component{
建造师(道具){
超级(道具)
此.state={
isEdit:错,
搜索文本:“”,
类别:this.props.category
}
this.handleClick=this.handleClick.bind(this);
this.handleClickOff=this.handleClickOff.bind(this);
this.updateSearch=this.updateSearch.bind(this);
}
componentDidMount(){
this.props.fetchTodos();
}
组件将接收道具(下一步){
this.setState({category:nextrops.category})
}
handleClick(e){
e、 停止传播();
this.setState({isEdit:true});
}
把手舔掉(e){
this.setState({isEdit:false});
}
更新搜索(e){
this.setState({searchText:e});
}
render(){
让searchText=this.state.searchText;
让category=this.state.category;
const{todo,receiveTodo,removeTodo,createTodo,deletetetodo,updateTodo}=this.props;
让我们去做一些事情;
如果(类别==“保留”){
todoItems=todos.map(函数(todo){
if((searchText==''|| todo.title.includes(searchText)| | todo.body.includes(searchText))&&&(todo.archive===false&&todo.trashed==false)){
返回
}
}
);
}else if(类别==“存档”){
todoItems=todos.map(函数(todo){
if((searchText==''|| todo.title.includes(searchText)| | todo.body.includes(searchText))&&&(todo.archive===true&&todo.trashed==false)){
返回
}
}
);
}否则如果(类别==“垃圾”){
todoItems=todos.map(函数(todo){
if((searchText==“”| | todo.title.includes(searchText)| | todo.body.includes(searchText))&&todo.trashed==true){
返回
}
}
);
}
让它形成;
如果(类别==“垃圾”| |类别==“存档”){
表格=
}否则{
表单=(!this.state.isEdit)?:
}
返回(
//在此处添加handleClickOff或其他解决方案。
{form}
{todoItems}
)}
}
将默认值导出到列表;
从此组件中拉入待办事项列表项
import React from 'react';
import { uniqueId } from '../../util/id_generator';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSearch, faDrumstickBite, faThList, faArchive } from '@fortawesome/free-solid-svg-icons';
import OutsideClickHandler from 'react-outside-click-handler';
class TodoListItem extends React.Component{
constructor(props) {
super(props);
this.state = {
todo: this.props.todo,
color: this.props.todo.color,
title: this.props.todo.title,
body: this.props.todo.body,
archive: false,
editing: false,
id: this.props.todo.id,
optionsOpen: false,
isHovering: false,
trashed: this.props.todo.trashed
}
this.update = this.update.bind(this);
this.handleUpdate = this.handleUpdate.bind(this);
this.archive = this.archive.bind(this);
this.openOptions = this.openOptions.bind(this);
this.handleMouseHover = this.handleMouseHover.bind(this);
this.handleClose = this.handleClose.bind(this);
this.clickOffNote = this.clickOffNote.bind(this);
}
update(property) {
return e => this.setState({ [property]: e.target.value });
}
handleUpdate(e) {
e.preventDefault();
const todo = Object.assign({}, this.state, { id: this.state.id });
this.props.updateTodo(todo);
this.setState({editing: false});
}
openOptions(e) {
e.preventDefault();
if (this.state.optionsOpen === false) {
this.setState({ optionsOpen: true })
} else {
this.setState({ optionsOpen: false })
}
}
handleMouseHover() {
this.setState({isHovering: true});
}
handleClose(){
if(this.state.optionsOpen === false){
this.setState({isHovering: false})
}
}
clickOffNote(){
this.setState({editing:false, optionsOpen: false, isHovering: false});
}
archive() {
this.setState(prevState => ({
...prevState,
archive: !prevState.archive
}), () => {
const todo = Object.assign({}, this.state, { id: this.state.id });
this.props.updateTodo(todo)
})
}
render(){
const {todo, removeTodo, deleteTodo, updateTodo} = this.props;
let color;
color = this.props.todo.color + "Note";
let steev;
let options;
if(this.state.editing === true){
steev = <div className={color}>
<input className="title" placeholder={this.state.title} onChange={this.update('title')} />
<label className="formBodyContainer">
<textarea className="formBody" placeholder={this.state.body} onChange={this.update('body')} />
</label>
<button className="editButton" onClick={this.handleUpdate}>Submit Edit</button>
</div>
} else {
steev =
<div className="test" >
<div className={color} onMouseEnter={this.handleMouseHover}
onMouseLeave={this.handleClose}>
<div className="noteTitle">{this.state.title}</div>
<div className="noteBody">{this.state.body}</div>
{
this.state.isHovering &&
<div>
<FontAwesomeIcon icon="ellipsis-v" className="noteOptionsToggle" onClick={this.openOptions} />
<FontAwesomeIcon icon="archive" className="archiveOptionsToggle" onClick={this.archive} />
</div>
}
{
this.state.isHovering === false &&
<div className="optionsHolder">
</div>
}
{
this.state.optionsOpen &&
<OutsideClickHandler onOutsideClick={this.clickOffNote}>
<div className="options">
<button className="deleteButton" onClick={() => this.setState({ editing: true, optionsOpen: false })}>Edit Steev</button>
<button className="deleteButton" onClick={() => deleteTodo(todo)}>Delete Steev</button>
</div>
</OutsideClickHandler>
}
</div>
</div>
}
return(
<div>
{steev}
{options}
</div>
)}
}
export default TodoListItem;
从“React”导入React;
从“../../util/id_生成器”导入{uniqueId};
从“@fortawesome/react fontawesome”导入{FontAwesomeIcon}
从“@fortwome/free solid svg icons”导入{faSearch、faDrumstickBite、faThList、faArchive};
从“反应外部点击处理程序”导入外部点击处理程序;
类TodoListItem扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
待办事项:这个。道具。待办事项,
颜色:this.props.todo.color,
标题:this.props.todo.title,
body:this.props.todo.body,
档案:错,
编辑:错,
id:this.props.todo.id,
选项打开:错误,
isHovering:错,
垃圾:这个。道具。待办事项。垃圾
}
this.update=this.update.bind(this);
this.handleUpdate=this.handleUpdate.bind(this);
this.archive=this.archive.bind(this);
this.openOptions=this.openOptions.bind(this);
this.handlemousehave=this.handlemousehave.bind(this);
this.handleClose=this.handleClose.bind(this);
this.clickOffNote=this.clickOffNote.bind(this);
}
更新(属性){
返回e=>this.setState({[property]:e.target.value});
}
手动更新(e){
e、 预防默认值();
const todo=Object.assign({},this.state,{id:this.state.id});
this.props.updateTodo(todo);
this.setState({editing:false});
}
开放选项(e){
e、 预防默认值();
if(this.state.options打开===false){
this.setState({optionsOpen:true})
}否则{
this.setState({optionOpen:false})
}
}
手鼠悬停{
this.setState({isHovering:true});
}
handleClose(){
if(this.state.options打开===false){
this.setState({isHovering:false})
}
}
clickOffNote(){
this.setState({editing:false,optionopen:false,isHovering:false});
}
档案馆(){
this.setState(prevState=>({
…国家,
存档:!prevState.archive
}), () => {
const todo=Object.assign({},this.state,{id:this.state.id});
this.props.updateTodo(todo)
})
}
render(){
const{todo,removeTodo,deletetetodo,up
import TodoListItem from './todo_list_item';
import TodoForm from './todo_form';
import Preclick from './preclick_form';
import Nav from './nav_container.jsx';
class TodoList extends React.Component{
constructor(props){
super(props)
this.state = {
isEdit: false,
searchText: '',
category: this.props.category
}
this.handleClick = this.handleClick.bind(this);
this.handleClickOff = this.handleClickOff.bind(this);
this.updateSearch = this.updateSearch.bind(this);
}
componentDidMount() {
this.props.fetchTodos();
}
componentWillReceiveProps(nextProps){
this.setState({category: nextProps.category})
}
handleClick(e) {
e.stopPropagation();
this.setState({ isEdit: true });
}
handleClickOff(e){
this.setState({ isEdit: false });
}
updateSearch(e){
this.setState({searchText: e});
}
render() {
let searchText = this.state.searchText;
let category = this.state.category;
const { todos, receiveTodo, removeTodo, createTodo, deleteTodo, updateTodo } = this.props;
let todoItems;
if(category === "keeps"){
todoItems = todos.map(function(todo){
if ((searchText === '' || todo.title.includes(searchText) || todo.body.includes(searchText)) && (todo.archive === false && todo.trashed === false)){
return <TodoListItem
key={`todo-list-item${todo.id}`}
todo={todo}
receiveTodo={receiveTodo}
removeTodo={removeTodo}
deleteTodo={deleteTodo}
updateTodo={updateTodo}
/>
}
}
);
} else if(category === "archive"){
todoItems = todos.map(function (todo) {
if ((searchText === '' || todo.title.includes(searchText) || todo.body.includes(searchText)) && (todo.archive === true && todo.trashed === false)) {
return <TodoListItem
key={`todo-list-item${todo.id}`}
todo={todo}
receiveTodo={receiveTodo}
removeTodo={removeTodo}
deleteTodo={deleteTodo}
updateTodo={updateTodo}
/>
}
}
);
} else if(category === "trash"){
todoItems = todos.map(function (todo) {
if ((searchText === '' || todo.title.includes(searchText) || todo.body.includes(searchText)) && todo.trashed === true) {
return <TodoListItem
key={`todo-list-item${todo.id}`}
todo={todo}
receiveTodo={receiveTodo}
removeTodo={removeTodo}
deleteTodo={deleteTodo}
updateTodo={updateTodo}
/>
}
}
);
}
let form;
if(category === "trash" || category === "archive"){
form = <div className="no-form"></div>
} else {
form = (!this.state.isEdit) ? <Preclick /> : <TodoForm receiveTodo={receiveTodo} createTodo={createTodo} sessionId={this.props.sessionId} />
}
return (
// add handleClickOff here or another solution.
<div onClick={this.handleClickOff}>
<Nav updateSearch = {this.updateSearch}/>
<div className="formToggle" onClick={this.handleClick}>
{form}
</div>
<div className="notes">
{todoItems}
</div>
</div>
)}
}
export default TodoList;
import React from 'react';
import { uniqueId } from '../../util/id_generator';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSearch, faDrumstickBite, faThList, faArchive } from '@fortawesome/free-solid-svg-icons';
import OutsideClickHandler from 'react-outside-click-handler';
class TodoListItem extends React.Component{
constructor(props) {
super(props);
this.state = {
todo: this.props.todo,
color: this.props.todo.color,
title: this.props.todo.title,
body: this.props.todo.body,
archive: false,
editing: false,
id: this.props.todo.id,
optionsOpen: false,
isHovering: false,
trashed: this.props.todo.trashed
}
this.update = this.update.bind(this);
this.handleUpdate = this.handleUpdate.bind(this);
this.archive = this.archive.bind(this);
this.openOptions = this.openOptions.bind(this);
this.handleMouseHover = this.handleMouseHover.bind(this);
this.handleClose = this.handleClose.bind(this);
this.clickOffNote = this.clickOffNote.bind(this);
}
update(property) {
return e => this.setState({ [property]: e.target.value });
}
handleUpdate(e) {
e.preventDefault();
const todo = Object.assign({}, this.state, { id: this.state.id });
this.props.updateTodo(todo);
this.setState({editing: false});
}
openOptions(e) {
e.preventDefault();
if (this.state.optionsOpen === false) {
this.setState({ optionsOpen: true })
} else {
this.setState({ optionsOpen: false })
}
}
handleMouseHover() {
this.setState({isHovering: true});
}
handleClose(){
if(this.state.optionsOpen === false){
this.setState({isHovering: false})
}
}
clickOffNote(){
this.setState({editing:false, optionsOpen: false, isHovering: false});
}
archive() {
this.setState(prevState => ({
...prevState,
archive: !prevState.archive
}), () => {
const todo = Object.assign({}, this.state, { id: this.state.id });
this.props.updateTodo(todo)
})
}
render(){
const {todo, removeTodo, deleteTodo, updateTodo} = this.props;
let color;
color = this.props.todo.color + "Note";
let steev;
let options;
if(this.state.editing === true){
steev = <div className={color}>
<input className="title" placeholder={this.state.title} onChange={this.update('title')} />
<label className="formBodyContainer">
<textarea className="formBody" placeholder={this.state.body} onChange={this.update('body')} />
</label>
<button className="editButton" onClick={this.handleUpdate}>Submit Edit</button>
</div>
} else {
steev =
<div className="test" >
<div className={color} onMouseEnter={this.handleMouseHover}
onMouseLeave={this.handleClose}>
<div className="noteTitle">{this.state.title}</div>
<div className="noteBody">{this.state.body}</div>
{
this.state.isHovering &&
<div>
<FontAwesomeIcon icon="ellipsis-v" className="noteOptionsToggle" onClick={this.openOptions} />
<FontAwesomeIcon icon="archive" className="archiveOptionsToggle" onClick={this.archive} />
</div>
}
{
this.state.isHovering === false &&
<div className="optionsHolder">
</div>
}
{
this.state.optionsOpen &&
<OutsideClickHandler onOutsideClick={this.clickOffNote}>
<div className="options">
<button className="deleteButton" onClick={() => this.setState({ editing: true, optionsOpen: false })}>Edit Steev</button>
<button className="deleteButton" onClick={() => deleteTodo(todo)}>Delete Steev</button>
</div>
</OutsideClickHandler>
}
</div>
</div>
}
return(
<div>
{steev}
{options}
</div>
)}
}
export default TodoListItem;
handleArchive() {
this.setState(prevState => ({
...prevState,
archive: !prevState.archive
}), () => {
const todo = Object.assign({}, this.state, { id: this.state.id });
this.props.updateTodo(todo)
})
}