组件需要两次单击而不是一次单击来更新

问题描述

我有一个按钮,应该将我的笔记存档并将其发送到单独的存档选项卡。我具有以下设置,但是,当我单击以存档该帖子时,它将需要一击,而单击以取消存档该帖子将需要两次。我相信这是因为setstate是在更新调用之后异步发生的,但是我不确定解决方案。我试过为存档调用的更新制作一个单独的函数,但是没有运气。有什么想法吗?

我还不能嵌入图像,所以这是有问题的代码。

https://imgur.com/a/VmznD5D

完整的代码故障(目前马虎)。

此组件确定通过道具传递到待办事项列表的类别。

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>
        )
    }
}

容器

import TodoList from './todo_list';
import {createTodo,deleteTodo,fetchTodos,receiveTodos,updateTodo,receiveTodo,removeTodo } from '../../actions/todo_actions';
import { allTodos } from '../../reducers/selectors';

const mapStateToProps = state => ({
    todos: allTodos(state),sessionId: state.session.id,state
});

const mapDispatchToProps = dispatch => ({
    receiveTodo: todo => dispatch(receiveTodo(todo)),removeTodo: todo => dispatch(removeTodo(todo)),fetchTodos: () => dispatch(fetchTodos()),createTodo: todo => dispatch(createTodo(todo)),deleteTodo: todo => dispatch(deleteTodo(todo)),updateTodo: todo => dispatch(updateTodo(todo))
});

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

容器中的组件将根据通过componentWillReceiveProps中的props向下推的类别进行渲染(我需要更改它的日期,但它似乎正在起作用)

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,removeTodo,createTodo,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,isHovering: false});
    }

    archive() {
        this.setState(prevState => ({
            ...prevState,archive: !prevState.archive
        }),() => {
            const todo = Object.assign({},{ id: this.state.id });
            this.props.updateTodo(todo)
        })
    }

    render(){
        const {todo,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;

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)