2019-07-08 | UNLOCK | 更新时间:2019-7-9 17:18

React在开发中遇到的需求与问题

需求:点击按钮出现弹窗,点击空白地方弹窗消失

关联的问题:e.stopPropgation() 不起作用;

这种需求在我看来说很简单的,给document 绑定 click事件,点击后选择关闭弹窗,在窗体使用 e.stopPropgation() 来阻止冒泡行为。思路是这样,但是在React 中却不能单纯如此,因为e.stopPropgation() 不能阻止冒泡行为的发生,原因在于react 把事件绑定委托给document ,当你阻止冒泡的时候,document 早就接受到了点击事件,需要使用React 的e.nativeEvent

const [show,setShow]=useState(false)
const Clik=(e)=>{
  e.stopImmediatePropagation()
  setShow(false)
}
useEffect(()=>{
  document.addEventListener('click',Clik)
  return ()=>{document.removeEventListener('click',Clik)}
},[show])
...

// 以show 作为关闭窗口的开关 
{show?
  <div onClick=(e)=>{e.nativeEvent.stopImmediatePropagation();} >窗体</div>:
''}

当然在开发过程中遇到了一些问题,如:react 在 document 上绑定事件的时候,获取的 state 是初始化的,react 在路由改变后重新进入的时候,绑定的改变状态的事件还在,组件却不对其做出改变了,当然这些问题与需求是 Hooks 的使用不规范所导致的问题,在你将其不规范的地方改正后,这些问题都会消失

问题:用户短时间内点击多次所产生的多次请求的问题

关联的问题:中断之前的网络请求;防止用户的多次点击;函数节流与防抖

这样的问题,在很多情况下都会出现,这涉及到前端的一些解决思路节流和防抖。

以按钮点击来举例节流和防抖

函数节流:以固定的频率执行执行函数,不管你点击多快,没达到设定的时间就不执行
函数防抖:类似游戏的释放法术,只要你点击了就会重新读条,读条完成才会执行函数

中断网络请求

不同的框架封装着不同的打断方式,

JS与JQ
//方法就是将XHR对象指向currentAjax,再调用currentAjax的.abort()来中止请求 

var currentAjax = null;  
function startAjax(){  
  if(currentAjax) {currentAjax.abort();} 
  currentAjax = $.ajax({
    type:'POST',
    beforeSend:function(){},  
    url:'test.php',  
    data:'username=xxx',  
    dataType:'JSON',  
    error:function(){alert('error')},  
    success:function(data){alert(data)}  
  });  
}  

Angular
//通过注入 `$q` 服务,使用`$q.defer`来停止

var _enj;
$scope.clconversations=function(){
    if(_enj){_enj.resolve()};
    _enj = $q.defer();
    $http.get('/Iridium/public/tcpanalysis/getconversations',{
        params:{
            start_time: $scope.start_time,
            end_time:$scope.end_time,
        },
        timeout:_enj.promise
    }).then(function(response){
        console.log('')
	});
}

需求:数据表格,要求竖向滚动,表头固定,横向滚动,表头能跟随

关联的问题,传统表格中 display:table 系列和高度产生滚动条的冲突

这样的问题在很多时候我们都会遇到,在 Html 中,可以通过 html + js 的方式创建 div 模拟 table 表格来进行展示。
在react中,我需要把它单独抽出,这样其他地方时候也能用到。

import * as React from 'react'
var $ = require('jquery')
export class LTable extends React.Component<any,any>{
  constructor(props:any) {
    super(props);
    this.resize=this.resize.bind(this)
    this.state = {
      id:this.props.id||'l_'+(new Date().getTime()+Math.random()).toFixed(3),
      clas:this.props.className||'',
      height:this.props.height||'300px',
    }
  }
  static contextTypes={  
    router: function(){
      return null
    }
  }
  mounted = false;
  componentWillMount(){
    this.mounted = true;
  }
  componentDidMount() {
    window.addEventListener('resize', this.resize)
    this.resize()
  }
  componentDidUpdate(){
    this.resize()
  }
  componentWillUnmount(){
    window.removeEventListener('resize',this.resize);
    this.mounted = false;
  }
  resize(){
    let id=this.state.id
    let tbody=this.props.tbody
    if(tbody.length>0){
      let ltable=document.getElementById(id)!.getElementsByTagName('table')
      let thead0=ltable[0].getElementsByTagName('thead')[0]
      let thead1=ltable[1].getElementsByTagName('thead')[0]
      let ltbody=document.getElementById(id)!.getElementsByClassName('l_table_body')[0]
      let th0=thead0.getElementsByTagName('th')
      let th1=thead1.getElementsByTagName('th')
      thead0.style.minWidth=thead1.offsetWidth+'px'
      ltable[0].style.width=ltable[1].offsetWidth+'px'
      for(let i=0;i<th1.length;i++){
        th0[i].style.width=th1[i].offsetWidth+'px'
      }
      $(ltbody).scroll(function(e:any){
        let div=document.getElementById(id)!.getElementsByClassName('l_table_head')[0]
        div.scrollLeft=e.target.scrollLeft
      })
    }
  }
  render(){
    let thead=this.props.thead,tbody=this.props.tbody
    return (
    <div id={this.state.id} className={"l_table "+this.state.clas}>
      {this.props.title?
        <h3 className="l_table_title">{this.props.title}</h3>:''
      }
      <div className="l_table_head l_scroll_hide">
        <table>
          <thead>
            <tr>
            {thead.map((e:any,i:any)=>
              <th key={i}>{e.title}</th>
            )}
            </tr>
          </thead>
        </table>
      </div>
      <div className="l_table_body" style={{height:this.state.height}}>
        {tbody.length>0?
        <table>
          <thead>
            <tr>
            {thead.map((e:any,i:any)=>
              <th key={i}>{e.title}</th>
            )}
            </tr>
          </thead>
          <tbody>
            {tbody.map((tr:any,a:any)=>
              <tr key={a}>
              {thead.map((td:any,b:any)=>{
                if(td.render){
                  return <td key={b}>{td.render(tr)}</td>
                }else{
                  return <td key={b}>{td.title}</td>
                }
              })}
              </tr>
            )}
          </tbody>
        </table>:
        <div className="l_nodata">
          <span>No Date</span>
        </div>
        }
      </div>
    </div>
    )
  }
}