带点脑子 發表於 2019-5-25 10:14:00

react项目经验

<h4 id="调用后返回上一页跳转至当前页">调用后返回上一页&amp;&amp;跳转至当前页</h4>
<pre><code> this.props.history.goBack();   返回
this.props.history.push("/index/setting/basicsetting"); 跳转
this.props.history.go(-1)跳转

当使用时出现以下错误Cannot read property 'push' of undefined,
因为父组件调用子组件定义的跳转事件时,要传递history,这里history未定义
(比如app.js这个组件,一般是首页,不是通过路由跳转过来的,而是直接从浏览器中输入地址打开的,如果不使用withRouter此组件的this.props为空,没法执行props中的history、location、match等方法)
解决方法:
import React from "react";
import {withRouter} from "react-router-dom";   //第一,引入withRouter

class MyComponent extends React.Component {   
...
myFunction() {
    this.props.history.push("/some/Path");
}
...
}
export default withRouter(MyComponent);   //第二,不要在上面暴露模块,在这里使用withRouter暴露模块

详细可见:react-router v4 使用 history 控制路由跳转   https://github.com/brickspert/blog/issues/3
</code></pre>
<h4 id="调用后重新渲染当前页跳转至当前页">调用后重新渲染当前页&amp;&amp;跳转至当前页</h4>
<pre><code> this.props.history.go(0)跳转



state={
   visible:false
}
handleClick=()=&gt;{
    this.setState({
       visible:true
   });
   }
this.setState(this.state)//此语句执行过后页面重新渲染state。这里需要注意的事重新渲染会将visible渲染成state里的false,而不是handleClick里的true
//渲染会把state里的内容全部重新渲染,即执行this.setState(state)之后,visible会被重新渲染为false,若需要visible为true,可以在渲染之后重新定义状态,如下重新定义
this.setState({this.state})
this.setState({
      visible:true
   });



定义componentWillMount=async()=&gt;{   
      this.getData(); //重新渲染当前页面
    }// 使用:调用this.getData();函数即可
    async getData(){
      代码段
    }

</code></pre>
<h4 id="代码解析">代码解析</h4>
<pre><code>let {state}=this;// 即 let state = this.state;

let res = await api.SettingGetInfo(this.props.match.params)   //获取列表里当前元素的id值,此方法需要注意有一个必要条件在route页面里的route添加/:id
//即&lt;Route path="/index/setting/basicsetting/:id" component={BasicSettting} /&gt;


rowKey={record=&gt;record.id}    //表格table中的每个记录应该有唯一的“key”支持,或者将“rowKey”设置为唯一的主键,否则会报错。这里是给表格设置rowKey
</code></pre>
<h4 id="点击按钮复制相关内容这里以复制链接为例">点击按钮复制相关内容(这里以复制链接为例)</h4>
<pre><code>npm i --save copy-to-clipboard   //首先安装相关包

import copy from 'copy-to-clipboard';//引入模块

render:(a, code, index)=&gt;{
                return &lt;span&gt;
                  &lt;a href="# "onClick={()=&gt;{this.copyLink(code)}}&gt;复制链接&lt;/a&gt;
                &lt;/span&gt;
            }

copyLink=(code)=&gt;{
      copy(`https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=${code.info}`)
      message.success("链接复制成功",2.5)
    }

</code></pre>
<h4 id="三目运算符的嵌套使用">三目运算符的嵌套使用</h4>
<pre><code>正常使用:code.type===1?(adate&lt;bdate?atime:btime):&lt;span className="text-success"&gt;永不&lt;/span&gt;

react里:{title:"时间",dataIndex:"Time",render(a,code,index){
                let adate=...;
                let bdate=...;
                var overtime=&lt;span className="text-danger"&gt;时间不足&lt;/span&gt;;
                var forevertime=&lt;span className="text-success"&gt;永久&lt;/span&gt;
                var times=`${date.getFullYear()}-${date.getMonth() + 1&lt;10?"0"+(date.getMonth()+1):date.getMonth()+1}-${date.getDate()&lt;10?"0"+date.getDate():date.getDate()} ${date.getHours()&lt;10?"0"+date.getHours():date.getHours()}:${date.getMinutes()&lt;10?"0"+date.getMinutes():date.getMinutes()}:${date.getSeconds()&lt;10?"0"+date.getSeconds():date.getSeconds()}`   //将时间戳转换为日期格式

                return &lt;span&gt;{code.type===1?(adate&lt;bdate?overtime:times):forevertime}&lt;/span&gt;//嵌套使用
            }}
</code></pre>
<p>======================================================================================================================================================</p>
<h2 id="接口部分">接口部分</h2>
<h4 id="读懂接口文档">读懂接口文档</h4>
<pre><code>
/api/wechat/code/:officialId/:qrcodeId带冒号,动态数据:`${base}/api/wechat/code/${localStorage.getItem("listid")}/${params.id}`//这列的:qrcodeId需要使用${params.id}动态写入,params即数组
/api/wechat/statistics/:officialId/code不带冒号,静态的:`${base}/api/wechat/statistics/${localStorage.getItem("listid")}/code`//这里的qrcode直接写上去就可以

</code></pre>
<h4 id="参数问题">参数问题</h4>
<pre><code>request&lt;T = any&gt;(config: AxiosRequestConfig): AxiosPromise&lt;T&gt;;   //request 一个参数config
get&lt;T = any&gt;(url: string, config?: AxiosRequestConfig): AxiosPromise&lt;T&gt;;//get两个参数 url config
delete(url: string, config?: AxiosRequestConfig): AxiosPromise;//delete两个参数url config
head(url: string, config?: AxiosRequestConfig): AxiosPromise;   //head两个参数 url config
post&lt;T = any&gt;(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise&lt;T&gt;;//post 三个参数 url data config
put&lt;T = any&gt;(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise&lt;T&gt;; // put 三个参数 url data config
patch&lt;T = any&gt;(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise&lt;T&gt;; // patch 三个参数 url data config

参数解释 :url —— 请求地址
                   data——发送给服务器的请求数据
                   config——配置,一般都是固定格式

举个栗子:
export default{
      async codeDesign(params){                                                
                return await axios.put(`${base}/api/code/${localStorage.getItem("listid")}/${params.id}`, params,{//url data
                        headers:{                         //config一般都是固定格式
                               "token":cookie.load("usertoken")
                        }
                }).then((res)=&gt;{
                      return res.data;
                });
       },
      async codeExtend(params){
      return axios.post(`${base}/api/code/${localStorage.getItem('listid')}/${params.id}/extend`,{},{   //这里data就没有传参,而是用{}表示
            headers:{
                "token":cookie.load("usertoken")
            }
      }).then((res)=&gt;{
            return res.data;
      });
    },
      async codeGetMsg(params){
            return await axios.get(`${base}/api/code/${localStorage.getItem("listid")}/${params.id}`,{
                  params,       **//如果是get delete两个参数的这种,是没有data参数的,那么params不能放在data里,就可以放在config里**
                  headers:{
                      "token":cookie.load("usertoken")
                  }
            }).then((res)=&gt;{
                  return res.data;
            });
          },
}

注意:需要的参数,一个都不能少,data如果不需要传,设置为{}都行,也不能不传

</code></pre>
<h4 id="axios实战举例">axios实战举例</h4>
<pre><code>state={

    //上传接口的参数
    title:"",   
    author:"",
    digest:"",
    content:"",

    piclist:[],   //从服务器获取的图片数组
    picTotal:2,   
    filter:{         
      isloading:false,
      type:"image",
      flag:2,
      page:1,
      pageSize:18,
      },
}

//上传pictextData数据到服务器
    addPictext=async()=&gt;{
      let {title,author,digest,content}=this.state.pictextData;
      if(!title){
            this.setState({
                pictextTitleRemind:true
            })
            return;
      }else{
            this.setState({
                pictextTitleRemind:false
            })
      }
      if(!(/^(((https?):\/\/|\w+(\.\w+)+)(:\w+)?).*/.test(contentSourceUrl))){   //匹配正则
            this.setState({
                urlRemind:true
            })
            return;
      }else{
            this.setState({
                urlRemind:false
            })
      }
      let data=await api.pictextAdd({
            title,
            author,
            digest,
            content,
      })
      if(data.code!==0){
            console.log(api.stateCode);
            return;
      }
      if(data.code===0){
            message.success("保存成功!",3);
            this.props.history.push("/index/setting/pictextIndex");
      }
    }

componentWillMount=async()=&gt;{   //render加载之前就获取到图片信息
      this.getData();
    }

//获取图片的接口
async getData(){
      this.setState({
      filter: Object.assign(this.state.filter, {
            isloading: true
      }),
      
      });
      let res=await api.picGetList(this.state.filter)
   this.setState({
      filter: Object.assign(this.state.filter, {
            isloading: false
      }),
      if(res.code===0){
      this.state.picTotal=res.data.total;
      this.state.piclist=res.data.data;
      }else{
      console.log(api.stateCode);
      }
      this.setState(this.state);//重新渲染页面
    }

//分页
    onChangePage = (page = 1, pageSize = 18) =&gt; {
      this.setState(
          Object.assign(this.state.filter, {
            page,pageSize
          })
      );
      this.getData();//重新加载getData函数,为了重新渲染页面
    }

//删除图片接口
    deletePic=async(item)=&gt;{
      this.setState({
      imgDelete:false,
      picImgDelete:false,
      })
      let data=await api.picDelete({
      id:item.id,    //获取需要删除的图片的id
      })
      if(data.code!==0){
      console.log(api.stateCode);
      return;
      }else if(data.code===0){
      this.onChangePage();
      message.success(`删除成功!`,2.5);
      }
      this.getData();
    }

&lt;Pagination hideOnSinglePage onChange={this.onChangePage} current={this.state.filter.page} pageSize={this.state.filter.pageSize} total={this.state.picTotal}/&gt;//antd分页页标
</code></pre>
<h4 id="受控组件和不受控组件">受控组件和不受控组件</h4>
<pre><code>在HTML中,&lt;textarea&gt; 的值是通过子属性设置的。在React中,需要通过value设置。我们可以通过添加事件属性onChange监听内容的变化,onChange会在下列情况下被触发:
input或者textarea的内容改变
input的checked状态改变
select的状态改变

【受控组件】
设定了value的input就是一个受控组件。input里会一直展现这个值,用户的任何输入都是无效的。如果你想随着用户的输入改变,使用onChange事件,或者将value改为defaultValue

【非受控组件】
value没有值或者值设为null的input是一个不受控组件。用户的任何输入都会反映到输入框中
这个时候也可以监听onChange事件,内容的改变也会触发事件。
可以通过defaultValue给input设置默认值
</code></pre>
<h4 id="指定编辑如删除更新等">指定编辑(如删除,更新等)</h4>
<pre><code>有一种需求是点击table中当前tr的“编辑”按钮后,跳转到新的编辑页面编辑当前tr的信息。
这种情况是需要动态获取id的
方法如下:
1、在route.js即路由页面将编辑页面的路由给一个/:id,如下
&lt;Route path="/index/setting/code/code-edit/:id" component={codeEdit} /&gt;   //注意是/:id/别忘了
2、列表页面编辑按钮的Link跳转给一个动态id(该id由后端接口数据里给出),如下
&lt;Link to={`/index/setting/code/code-edit/${codelist.id}?id=${codelist.id}`} className="mr-10px"&gt;编辑&lt;/Link&gt;
3、在编辑页面对接接口时,参数应使用this.props.match.params
async getPictextData(){
      let res =await api.pictextGetEdit(this.props.match.params)   //这里传入的是this.props.match.params
      if(res.code===0){
            state.pictextEditData=res.data;
      }else{
            console.log(api.stateCode);
      }
      this.setState(state)
      }

提个醒:this.props.match.params是从另一个页面通过路由带到当前页面的数据。你可以在任何地方使用它。
这也表明了,这个传递的数据,不一定得是id,也可以是其他的数据。比如name,size等,通过/:name就可以传递
就比如说console.log(this.props.match.params)打印出来的是{"id":"1"}。你就可以通过this.props.match.params.id来获取到1。
但有一点,这个1可能是字符串类型的。和number类型的不是一个数据类型。所以在做判断是否相等的时候要注意,用==而不用===
在控制台打印出的数字,黑色的就是string类型。蓝色的是number类型

</code></pre>
<h4 id="使用搜索框搜索数据后端接口没有设置好全部由前端操作">使用搜索框搜索数据(后端接口没有设置好,全部由前端操作)</h4>
<pre><code>state={
    filter: {
                name:"",
                total: 0,
                page:1,
                pageSize:20,
            }
}

handleProductSearch=(e)=&gt;{
      this.setState(
            Object.assign(this.state.filter,{
                name:e.target.value,   //在对接接口之后。若想根据名称name搜索,将搜索框的event赋值给filter里的name便可
            })
      );
      this.setState(state);//重新渲染页面
    }


&lt;Search
    placeholder="请输入产品名称"
    onSearch={this.handleProductSearch}
/&gt;
</code></pre>
<h4 id="使用搜索框搜索数据后端接口已经设置好的情况下">使用搜索框搜索数据,(后端接口已经设置好的情况下)</h4>
<pre><code>state={
    filter: {
                name:"",
                total: 0,
                page:1,
                pageSize:20,
            }
}

productName=(e)=&gt;{
   this.setState(
            Object.assign(this.state.filter,{
                name:e.target.value,   //在对接接口之后。若想根据名称name搜索,将搜索框的值赋值给filter里的name便可
            })
      );
}

handleProductSearch=(e)=&gt;{
      this.productInfoGet();//调用获取产品信息的接口。此时的name已经是搜索的name。给接口接口会返回搜索后的结果
    }


&lt;Search
    placeholder="请输入产品名称"
    onChange={this.productName}
    onSearch={this.handleProductSearch}
/&gt;
</code></pre>
<p>======================================================================================================================================================</p>
<h4 id="localstorage解释">localStorage解释</h4>
<pre><code>    localStorage.setItem("key","value");//以“key”为名称存储一个值“value”

    localStorage.getItem("key");//获取名称为“key”的值

    localStorage.removeItem("key");//删除名称为“key”的信息。

    localStorage.clear();​//清空localStorage中所有信息
</code></pre>
<h4 id="state里的filter里得数据怎么setstate使用objectassign相关知识">state里的filter里得数据怎么setState?(使用Object.assign相关知识)</h4>
<pre><code>this.state={
            visible:false,
            filter: {
                isloading: false,
                name:"",
                page:1,
                pageSize:20,
            }
      }

这里的isloading怎么设置为true呢?

handleClick=()=&gt;{
      this.setState({
            filter:Object.assign(this.state.filter,{
                isloading:true
            }),
      });
    }
</code></pre>
<h4 id="动态添加css样式如通过点击添加css样式">动态添加css样式(如通过点击添加css样式)</h4>
<pre><code>state={
    select: "",
}

handleSelect=(item)=&gt;{
    this.setState({
      select: item.id
    })
}

&lt;div onClick={()=&gt;{this.handleSelect(item)}}style={{border:this.state.select===item.id?"1px solid #28a745":null}}&gt;&lt;/div&gt;
</code></pre>
<h3 id="动态添加一组可编辑框如点击添加按钮后会添加一个可输入数值的图文框">动态添加一组可编辑框(如点击添加按钮后会添加一个可输入数值的图文框)</h3>
<pre><code>思路:
1、state一个数组如Data,将数组的值与图文框绑定起来,通过map函数渲染到页面
2、当点击添加按钮后,执行函数,往list数组里push一组数据,数据会自动渲染到页面,即实现了动态添加图文框的功能
3、通过编辑数组的值即可动态编辑图文框里的内容
4、动态删除可以通过用数组的splice操作数组的下标index来实现删除。
总结:通过操作数组的数据来实现图文框的增删改,而不是通过dom操作

举个例子:
state={
    title:"",   //上传接口的参数
    author:"",
    digest:"",
    content:"",
    Data:[{id:"1",title:"",author:"",digest:"",content:""}],
    boxid:"1", //定义图文框的id
    msg:[],
    changeBorder:"",
}

//添加图文框数组
    addBox=()=&gt;{
      this.setState({
            boxid:this.state.boxid++,
      })
      this.state.Data.push({id:`${this.state.boxid}`,title:"",author:"",digest:"",content:""})
      this.setState(this.state)
    }
//删除图文框
listbox_Delete=(item)=&gt;{
      let index= this.state.Data.indexOf(item)    //获取需要删除的图文框的index
      this.state.Data.splice(index,1)    //使用splice方法删除数组数据
    }

//向上移动图文框(通过改变替换index来实现)
listbox_up=(item)=&gt;{
      let index=this.state.Data.indexOf(item)
      let arr=this.state.Data
      let index2=index-1
      if(index2!==0){
            arr=arr.splice(index2,1,arr)
      }
    }

//向下移动图文框
listbox_down=(item)=&gt;{
      let index=this.state.Data.indexOf(item)
      let arr=this.state.Data
      let index2=index+1
      if(index2!==arr.length){
            arr=arr.splice(index2,1,arr)
      }
    }

//图文框数组map方式渲染到页面
{
         this.state.Data.map((item,index)=&gt;{
         if(item.id==1){   //item.id==1时是主图文框的样式,否则是副图文框的样式
         return &lt;div onClick={()=&gt;{this.handleSelect(item)}} key={index}&gt;   //map语法必须要带有key={index},不然会报错
                         &lt;div&gt;
                           &lt;img src={item.picUrl} alt="" style={{width:"100%",height:"100%"}}/&gt;
                         &lt;/div&gt;
                         {item.title?&lt;div className="indexbox_mask"&gt;{item.title}&lt;/div&gt;:null}
                     &lt;/div&gt;
                  }else{
               return &lt;divkey={index} style={{border:this.state.changeBorder===item.id?"2px solid #28a745":null}} onClick={()=&gt;{this.handleSelect(item)}}&gt;    //handleSelect,点击后选取当前框并与输入框绑定
                              &lt;h4 style={{height:21}}&gt;{item.title}&lt;/h4&gt;
                              &lt;div className="listbox_content"&gt;
                                    &lt;div className="listbox_img"&gt;
                                          &lt;img src={item.picUrl} alt=""/&gt;
                                    &lt;/div&gt;
                              &lt;/div&gt;
                              &lt;div className="listbox_mask"&gt;
                                    &lt;Icon type="up"className="listbox_icon mr-10px" onClick={()=&gt;{this.listbox_up(item)}} /&gt;//图文框位置上移
                                    &lt;Icon type="down" className="listbox_icon" onClick={()=&gt;{this.listbox_down(item)}} /&gt;//图文框位置下移
                                    &lt;div className="float-r"&gt;
                                           &lt;Icon type="delete"className="listbox_icon" onClick={()=&gt;{this.listbox_Delete(item)}}/&gt;   //删除图文框
                                    &lt;/div&gt;
                               &lt;/div&gt;
                        &lt;/div&gt;
                     }
               })
             }
    &lt;Button onClick={this.addBox}&gt;&lt;/Button&gt;//添加图文框

//点击图文框后选定当前图文框,并与Input输入框绑定,之后在Input里输入的值都会存在当前数组里。再点击其他图文框后执行同样的操作,最后所有图文框里采集的数据会全部存在Data数组里,通过接口将数组传入后台,再在另一个页面获取并渲染该组数据,即完成了前后端的一个交接流程。
handleSelect=(item)=&gt;{
      console.log(item)
      this.setState({
            msg:item,
            changeBorder:item.id,
            title:item.title,
            author:item.author,
            digest:item.digest,
            content:item.content,
      })
    }

handleGetTitle=(e)=&gt;{   //与Input标签之间进行双向绑定
      this.setState({
            title:e.target.value,
      })
      this.state.msg.title=e.target.value;    //使得输入框与当前选定的文本框绑定
    }

&lt;InputonChange={this.handleGetTitle} id={this.state.msg.id} value={this.state.title} placeholder="请输入标题"/&gt;
</code></pre>
<h4 id="antd图片上传">antd图片上传</h4>
<pre><code>//判断用户上传文件的格式,不符合提醒用户,符合则返回true
function beforeUpload(file) {
if(file.type!=='image/png'&amp;&amp;file.type!=='image/jpeg'&amp;&amp;file.type!=='image/jpg'&amp;&amp;file.type!=='image/gif'){
    message.error("上传失败!仅支持jpeg,png,jpg,gif图片格式");
    return false;
}else if(file.size/1024/1024&gt;4){
    message.error("上传失败!仅支持大小在4M以内的图片上传");
    return false;
}
return true;
}

//上传图片接口
    UploadImg=()=&gt;{
      let self= this;   
      return {
      name: 'media',
      action: ``,//这里写服务器地址
      headers: {    //设置请求头
          token: cookie.load('usertoken'),
      },
      onChange(info) {
          self.setState({
            uploadWaiting:true
          })
          if (info.file.status !== 'uploading') {
            console.log(info.file, info.fileList);
            self.setState({
            uploadWaiting:false,
            })
          }
          if (info.file.status === 'done') {
            message.success(`${info.file.name}上传成功!`);
            self.setState({
            uploadWaiting:false,
            })
            self.getData()
          } else if (info.file.status === 'error') {
            message.error(`${info.file.name}上传失败!`);
            self.setState({
            uploadWaiting:false,
            })
          }
      },
      }
    }

    &lt;Upload {...this.UploadImg()} beforeUpload={beforeUpload}&gt;&lt;Button&gt;上传图片&lt;/Button&gt;&lt;/Upload&gt;
</code></pre>
<h4 id="列表数据相关操作table">列表数据相关操作(table)</h4>
<pre><code>constructor(props){
      super(props);
      this.columns=[
            {title:"",
            dataIndex:"ticket",
            width:66,
            render:(record)=&gt;(&lt;img src={record} width="50px" alt="" /&gt;)   
            },
            {title:"产品名称",dataIndex:"name"},
            {title:"产品类型",dataIndex:"type", render(a, productlist, index){
                return &lt;span&gt;{productist.type || "无"}&lt;/span&gt;
            }},
            {title:"对应编码",dataIndex:"keyword"},
            {title:"生产时间",dataIndex:"createtime"},
            {title:"到期时间",dataIndex:"expiretime",render(a,productlist,index){
                let date=new Date(new Date(productlist.expireTime).getTime());
                let nowdate=new Date(new Date().getTime());
                var overtime=&lt;span className="text-danger"&gt;已过期&lt;/span&gt;;
                var forevertime=&lt;span className="text-success"&gt;永不&lt;/span&gt;
                var times=`${date.getFullYear()}-${date.getMonth() + 1&lt;10?"0"+(date.getMonth()+1):date.getMonth()+1}-${date.getDate()&lt;10?"0"+date.getDate():date.getDate()} ${date.getHours()&lt;10?"0"+date.getHours():date.getHours()}:${date.getMinutes()&lt;10?"0"+date.getMinutes():date.getMinutes()}:${date.getSeconds()&lt;10?"0"+date.getSeconds():date.getSeconds()}`
                return &lt;span&gt;{productlist.mode===1?(date&lt;nowdate?overtime:times):forevertime}&lt;/span&gt;
            }},
            {title:"操作",
            dataIndex:"operation",
            key:"operation",
            width:225,
            render:(a, qrcodelist, index)=&gt;{
                return &lt;span&gt;
                  &lt;a href="# " className="mr-10px" onClick={()=&gt;{this.copyLink(qrcodelist)}}&gt;复制链接&lt;/a&gt;
                  &lt;a href={`${productlist.ticket}`} target={"_blank"} download={`${productlist.name}`} className="mr-10px"&gt;下载产品&lt;/a&gt;
                  &lt;Link to={`/index/setting/product/product-edit/${productlist.id}?id=${productlist.id}`} className="mr-10px"&gt;编辑&lt;/Link&gt;
                  {productlist.mode===2 ? &lt;a href="# "onClick={()=&gt;{this.showModal2(productlist)}}&gt;删除&lt;/a&gt; : &lt;a href="# " onClick={() =&gt; {this.extendProduct(productlist)}}&gt;延时上架&lt;/a&gt;}
                &lt;/span&gt;
            }
            
      },
      ];
      this.state={
            visible:false,
            visible2:false,
            productlist:[],
            filter: {
                isloading: false,
                name:"",
                total: 0,
                page:1,
                pageSize:20,
            }
      }
      
    }


&lt;Table
columns={this.columns}
dataSource={this.state.productlist}
rowKey={record=&gt;record.id}    //表中的每个记录应该有唯一的“key”支持,或者将“rowKey”设置为唯一的主键,否则会报错。这里是给表格设置rowKey
pagination={{onChange:this.onChangePage, current: this.state.filter.page, pageSize: this.state.filter.pageSize , total: this.state.filter.total }} /&gt;

注意:这里涉及到两种render写法,两种写法的this指向不同,其他效果差不多
1、render:(a,b)=&gt;{
            let time=a,
            let overtime=b,
            return &lt;div&gt;......&lt;/div&gt;
       }
2、render(a,b){
      let time=a,
      let overtime=b,
      return &lt;div&gt;......&lt;/div&gt;
    }
                        
</code></pre>
<h4 id="滚动监听及回到顶部">滚动监听及回到顶部</h4>
<pre><code>state={
    backTop:false,
    backTopShow:false,
}

componentWillMount=()=&gt;{
      window.addEventListener("scroll",this.handleScroll,true)    //滚动监听
    }

handleScroll=()=&gt;{
      if(document.documentElement.scrollTop&gt;1000){
            this.setState({
                backTopShow:true,    //当滚动到距离顶部1000px的距离时,“回到顶部”按钮显示
            })
      }else{
            this.setState({
                backTopShow:false,
            })
      }
      if(document.documentElement.scrollTop===0){   //当滚动到 0时,清除定时器
            clearInterval(this.scrollTimes)
      }
    }

backToTop=()=&gt;{
      if(document.documentElement.scrollTop&gt;0){
            this.scrollTimes=setInterval(()=&gt;{
                document.documentElement.scrollTop=document.documentElement.scrollTop-60;
            },5)
      }
    }


{this.state.backTopShow?&lt;Button onClick={this.backToTop}&gt;回到顶部&lt;/Button&gt;:null}    //“回到顶部”按钮
</code></pre>
<h4 id="关于接口调用函数的写法">关于接口调用函数的写法</h4>
<pre><code>间接调用,被动触发式用这种写法,这种写法用onClick等主动触发可能会引起Cannot read property 'setState' of undefined错误
async userInfoGet(){
      let res=await api.getUserInfo()
      if(res.code===0){
            this.setState({
                userNickname:res.data.nickname
            })
      }else{
            console.log(api.stateCode);
      }
    }
componentWillMount(){
    this.userInfoGet()
}//在别的函数里间接触发
直接调用,主动触发式如onClick等,用这种写法
userInfoGet=async()=&gt;{
      let res=await api.getUserInfo()
      if(res.code===0){
            this.setState({
                userNickname:res.data.nickname
            })
      }else{
            console.log(api.stateCode);
      }
    }
&lt;Button onClick={this.userInfoGet}&gt;&lt;/Button&gt;//主动调用
</code></pre>
<h4 id="将reactcomponent外部的代码移入到其内部">将React.Component外部的代码移入到其内部</h4>
<pre><code>外部:
const props = {
name: 'file',
action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
headers: {
    authorization: 'authorization-text',
},
onChange(info) {
    if (info.file.status !== 'uploading') {
      console.log(info.file, info.fileList);
    }
    if (info.file.status === 'done') {
      message.success(`${info.file.name} file uploaded successfully`);
    } else if (info.file.status === 'error') {
      message.error(`${info.file.name} file upload failed.`);
    }
},
};

export default class Demo extends React.Component{}

内部:
export default class Demo extends React.Component{
    state={}
    pluginZipUpload=()=&gt;{
      let self=this;    //这里改动 let self=this
      return{   //这里改动return
            name: 'plugin',
            action: "https://www.mocky.io/v2/5cc8019d300000980a055e76",
            headers:{
                authorization: 'authorization-text',
            },
            onChange(info) {
            if (info.file.status !== 'uploading') {
                console.log(info.file, info.fileList);
            }
            if (info.file.status === 'done') {
                self.setState({
                  pluginAddFile:Object.assign(self.state.pluginAddFile,{   //这里this换成self
                        plugin: info.file.originFileObj
                  })
                })
                console.log(self.state.pluginAddFile.plugin)
            } else if (info.file.status === 'error') {
                message.error(`${info.file.name}上传失败`);
            }
            },
      }
      };

}
</code></pre>
<h4 id="如何知道函数里需要传几个参数或者判断函数里有几个参数">如何知道函数里需要传几个参数或者判断函数里有几个参数</h4>
<pre><code>es5里可以用arguments打印
es6里可以用拓展运算符...a方法
在函数里写入...params
handleUpload=(...a)=&gt;{}
console.log(...a)即可打印出来里面需要的参数

可搭配debugger使用
</code></pre><br><br>
来源:https://www.cnblogs.com/huihuihero/p/10921507.html
頁: [1]
查看完整版本: react项目经验