如何使用 usestate 和 setstate 而不是 this.setState 使用 react 和 typescript?

Posted

技术标签:

【中文标题】如何使用 usestate 和 setstate 而不是 this.setState 使用 react 和 typescript?【英文标题】:How to use usestate and setstate instead of this.setState using react and typescript? 【发布时间】:2020-09-16 18:38:06 【问题描述】:

我想使用 react 和 typescript 实现一个 DragAndDrop 组件,而且我是使用 react redux 的新手。

下面是 DragAndDrop 组件的样子,

class DragAndDrop extends Component 
    constructor(props) 
        super(props);
        this.state = 
            dragging: false,
        ; 
    

    componentDidMount() 
        this.drag_counter = 0;
        this.enable_drag_event_listeners();
    

    componentWillUnmount() 
        this.disable_drag_event_listeners();
    

    enable_drag_event_listeners = () => 
        document.addEventListener('dragenter', this.handle_drag_in);
        document.addEventListener('dragleave', this.handle_drag_out);
        document.addEventListener('dragover', this.handle_drag);
        document.addEventListener('drop', this.handle_drop);
    

    disable_drag_event_listeners = () => 
        document.removeEventListener('dragenter', this.handle_drag_in);
        document.removeEventListener('dragleave', this.handle_drag_out);
        document.removeEventListener('dragover', this.handle_drag);
        document.removeEventListener('drop', this.handle_drop);
    

    handle_drag = (e) => 
        if (!this.props.loading) 
            e.preventDefault();
            e.stopPropagation();
        
    

    handle_drag_in = (e) => 
        if (!this.props.loading) 
            e.preventDefault();
            e.stopPropagation();
            this.drag_counter++;
            if (e.dataTransfer.files) 
                this.setState(dragging: true);
            
        
    

    handle_drag_out = (e) => 
        if (!this.props.loading) 
            e.preventDefault();
            e.stopPropagation();
            this.drag_counter--;
            if (this.drag_counter === 0) 
                this.setState(dragging: false);
            
        
    

    handle_drop = (e) => 
        if (!this.props.loading) 
            e.preventDefault();
            e.stopPropagation();
            this.setState(dragging: false);
            if (e.dataTransfer.files && e.dataTransfer.files.length > 0) 
                this.props.handle_drop(e);
                e.dataTransfer.clearData();
                this.drag_counter = 0;
            
        
    

    render() 
        return (
            <div>
                this.state.dragging &&
                    <div>
                        <div className="drop_zone">
                            <div className="drop_zone_overlay"/>
                            <div className="drop_zone_text">
                            <div>Drop your files here</div>
                        </div>
                    </div>
                
                this.props.children
            </div>
        )
    

从上面的代码可以看出,我使用了this.state和this.setState、componentdidmount、componentdidupdate和componentwillunmount。

我想用react redux usestate,setstate之类的东西。

如何更改上述代码以使用 usestate 和 setstate,以及如何实现 componentdidmount、componentdidupdate、componentwillunmount 钩子。

我尝试了什么?

function DragAndDrop() 
    const [isdragging, setIsDragging] = React.useState(false);
    handle_drag = (e) => 
        if (!this.props.loading) 
            e.preventDefault();
            e.stopPropagation();
        
    

    handle_drag_in = (e) => 
        if (!this.props.loading) 
            e.preventDefault();
            e.stopPropagation();
            this.drag_counter++; //how do i set this with react redux and also this is not a class

            if (e.dataTransfer.files) 
                setIsDragging(true);
             
        
    

    handle_drag_out = (e) => 
        if (!this.props.loading) 
            e.preventDefault();
            e.stopPropagation();
            this.drag_counter--; // how to keep track of this counter
            if (this.drag_counter === 0) 
                setIsDragging(false);
              
        
    

    handle_drop = (e) => 
        if (!this.props.loading) 
            e.preventDefault();
            e.stopPropagation();
            setIsDragging(false);
            if (e.dataTransfer.files && e.dataTransfer.files.length > 0) 
                this.props.handle_drop(e);
                e.dataTransfer.clearData();
                this.drag_counter = 0; //how to keep track of this
            
        
    

    render() 
        return (
            <div>
                isdragging &&
                    <div>
                        <div className="drop_zone">
                            <div className="drop_zone_overlay"/>
                            <div className="drop_zone_text">
                                <div>Drop files here</div>
                            </div>
                        </div>
                    </div>
                
                this.props.children
            </div>
        )
    

有人可以帮我解决这个问题吗?谢谢。 react redux中如何考虑componentdidmount、componentdidupdate、componentwillunmount。

谢谢。

【问题讨论】:

你不能在函数组件中使用this 我认为你应该先阅读reactjs.org/docs/hooks-intro.html 好的,那么我如何修改这个组件以与 react、typescript 和 redux 一起使用。谢谢。 【参考方案1】:

const DragAndDrop: React.FC<any> = (props) => 
  const [dragging, setDragging] = React.useState(false);
  const [drag_counter, setDrag_counter] = React.useState(0);
  React.useEffect(() => 
    // componentDidMount()
    setDrag_counter(0);
    enable_drag_event_listeners();
    return () => 
      // componentWillUnmount()
      disable_drag_event_listeners();
    
  , []);

  function enable_drag_event_listeners() 
    document.addEventListener('dragenter', handle_drag_in);
    document.addEventListener('dragleave', handle_drag_out);
    document.addEventListener('dragover', handle_drag);
    document.addEventListener('drop', handle_drop);
  

  function disable_drag_event_listeners() 
    document.removeEventListener('dragenter', handle_drag_in);
    document.removeEventListener('dragleave', handle_drag_out);
    document.removeEventListener('dragover', handle_drag);
    document.removeEventListener('drop', handle_drop);
  

  function handle_drag(e) 
    if (!props.loading) 
      e.preventDefault();
      e.stopPropagation();
    
  

  function handle_drag_in(e) 
    if (!props.loading) 
      e.preventDefault();
      e.stopPropagation();
      setDrag_counter((prev)=>prev+1);
      if (e.dataTransfer.files) 
        setDragging(true);
      
    
  

  function handle_drag_out(e) 
    if (!props.loading) 
      e.preventDefault();
      e.stopPropagation();
      setDrag_counter((prev)=>prev-1);
      if (drag_counter === 0) 
        setDragging(false);
      
    
  

  function handle_drop(e) 
    if (!props.loading) 
      e.preventDefault();
      e.stopPropagation();
      setDragging(false);
      if (e.dataTransfer.files && e.dataTransfer.files.length > 0) 
        props.handle_drop(e);
        e.dataTransfer.clearData();
        setDrag_counter(0);
      
    
  
  return ( 
    <div>
    dragging &&
      <div>
      <div className = "drop_zone" >
        <div className = "drop_zone_overlay" / >
        <div className = "drop_zone_text" >
          <div> Drop your files here </div> 
        </div> 
      </div>
     
    
      props.children
     
    </div>
  )


【讨论】:

我在定义 enable 和 disable_drag_event_listeners 的地方出现错误,如下所示“enable_drag_event_listeners 函数使 useEffect 挂钩的依赖关系在每次渲染时都发生变化。将其移动到 useEffect 回调中。或者,包装enable_drag_event_listeners 进入它自己的 useCallback hook"

以上是关于如何使用 usestate 和 setstate 而不是 this.setState 使用 react 和 typescript?的主要内容,如果未能解决你的问题,请参考以下文章

使用立即需要该状态进行 API 调用的 useState 挂钩时,如何等待 setState 调用完成?

如何避免未使用的 setState 函数?可以在没有 setter 的情况下创建 React useState 吗?

如何在功能组件的状态对象中使用 setState?

如何使用我的反应应用程序中的 useState 钩子给出的 setState 方法增加状态对象的选定索引的计数

从带有回调的 this.setState 调用迁移到 useState 和 useEffect

反应useState钩子,用函数调用setState [重复]