的translate插件_知否 ?知否 ?React插件了解一下!
為什么選擇插件,而不是組件?
- 調用簡單 ?this.$toast("xxx") ,不必再模板中提前定義 , 動態插入移除
- 插件獨立于業務
- 更新不影響代碼邏輯,做到熱更新
- 抽象,封裝
- 適用于toast,Dialog,Alert,Message,picker,Actionsheet等組件
react-toast-alert demo地址
使用方法:
import?$?from?'@/component/Toast/index';...
$.toast({
?type:0,
?content:?"我是默認Toast",
?time:?1000,
?opacity:?.5,
?onSucc()?{
??console.log("我是Toast的回調!")
?}
?});
$.toast("我是默認Toast");
$.toast({
?type:3,
?content:?"我是默認loading",
?time:?1000,
});
setTimeout(()?=>?{??//3s后隱藏
?$.hide();
},?3000);
$.dialog({
?type:?0,
?opacity:0.5,
?title:?"我是title",
?content:?"我是content",
?btnSucc:?"我是成功",
?btnFail:?"我是取消",
?onSucc(e)?{
??e.stopPropagation();
??$.toast("我是默認Toast");
?},
?onFail(e)?{
??e.stopPropagation();
??console.log("我是失敗的回調!");
?}
});
Vue 插件
在Vue里,一般將toast,alert等非業務相關的寫成插件,掛載在Vue的原型鏈上,使用的時候直接this.$toast即可,非常方便!相關原理在這里就不說了,感興趣的可以查閱官網. 先看看Vue的插件寫法:
@/components/vue-toast/index.js
import?ToastComponent?from?"./vue-toast.vue";?//?引入先前寫好的vuevar?Toast?=?{};
//避免重復install,設立flag
Toast.installed?=?false;
Toast.install?=?function(Vue,?options?=?{
?type:?"success",?//success?fail??warning?loading?toast
?msg:?"操作成功",
?time:?1000,
?callback()?{
?}
})?{
?if(Toast.installed)?return;
?var?obj;
?Vue.prototype.$toast?=?(config?=?{},?type)?=>?{
??if(type?==?'close')?{
???obj?&&?obj.removeToast();
???return?false;
??}
??if(typeof?config=="object"){
???config?=?{
????...options,
????...config
???}
??}else{
???config?=?{
????...options,
????...{
?????type:?"toast",?
?????????????????msg:?config
????}
???}
??}
??
??//?如果頁面有toast則不繼續執行
??if(document.querySelector('.vue-toast'))?return;
??//?1、創建構造器,定義好提示信息的模板
??const?toastTip?=?Vue.extend(ToastComponent);
??obj?=?new?toastTip();
??for(var?property?in?config)?{
???obj[property]?=?config[property];
??}
??//刪除彈框
??obj.removeToast?=?function()?{
???document.body.removeChild(tpl);
??}
??//插入頁面
??let?tpl?=?obj.$mount().$el;
??document.body.appendChild(tpl);
??Toast.installed?=?true;
??if(['success',?'fail',?'warning','toast'].indexOf(config.type)?>?-1)?{
???setTimeout(()?=>?{
????obj.removeToast();
????obj.callback();
???},?config.time)
??}
??['close'].forEach(function(type)?{
???Vue.prototype.$toast[type]?=?function(msg)?{
????return?Vue.prototype.$toast({},?type)
???}
??});
?};
};
//?自動安裝??,有了ES6就不要寫AMD,CMD了
if(typeof?window?!==?'undefined'?&&?window.Vue)?{
?window.Vue.use(Toast)
};
export?default?Toast
@/components/vue-toast/vue-toast.vue
<template>??<div?class="mask?vue-toast">
????<div>
??????<div?class="toast"?v-if="['success',?'fail',?'warning','loading'].indexOf(type)?>?-1">
????????<div?class="icon"?v-if="['success',?'fail',?'warning'].indexOf(type)?>?-1">
??????????<div?v-if="type=='success'"?class="success-icon">div>
??????????<div?v-if="type=='fail'"?class="fail-icon">div>
??????????<div?v-if="type=='warning'"?class="warning-icon">div>
????????div>
????????<div?class="loading-icon"?v-else>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
??????????<span>span>
????????div>
????????<div?class="msg"?v-html="msg">div>
??????div>
??????<div?v-else?class="toast-msg"?v-html="msg">div>
????div>
??div>
template>
<script>export?default?{
??data()?{return?{msg:?"?",type:?"success"
????};
??}
};script>
<style?scoped="scoped?"?lang="less">
.mask?{
??width:?100%;
??height:?100%;
??background:?rgba(0,?0,?0,?0.4);
??position:?fixed;
??left:?0px;
??top:?0px;
??display:?flex;
??justify-content:?center;
??align-items:?center;
??z-index:?10000;
??.toast-msg?{
????font-size:?0.24rem;
????text-align:?center;
????position:?relative;
????transform:?translateX(-50%);
????color:?#fff;
????left:?50%;
????padding:?0.18rem?0.27rem;
????overflow:?hidden;
????border-radius:?4px;
????white-space:?nowrap;
????display:?block;
????background:?rgba(0,?0,?0,?0.7);
??}
??.toast?{
????font-size:?0rem;
????padding:?0.27rem?.090rem;
????width:?2.26rem;
????overflow:?hidden;
????display:?flex;
????align-items:?center;
????flex-direction:?column;
????color:?#f2f2f2;
????background:?rgba(51,?51,?51,?0.94);
????border-radius:?0.09rem;
????text-align:?center;
????.icon?{
??????width:?0.72rem;
??????height:?0.72rem;
??????border-radius:?50%;
??????border:?1px?solid?#f2f2f2;
??????position:?relative;
??????justify-content:?center;
??????align-items:?center;
??????display:?flex;
??????
??????position:?relative;
??????.success-icon?{
????????border-right:?1px?solid?#f2f2f2;
????????border-bottom:?1px?solid?#f2f2f2;
????????transform:?rotate(45deg);
????????width:?0.27rem;
????????height:?0.45rem;
????????margin-top:?-0.18rem;
??????}
??????.fail-icon?{
????????&:before?{
??????????content:?"?";
??????????position:?absolute;
??????????top:?50%;
??????????left:?50%;
??????????transform:?translate(-50%,?-50%)?rotate(45deg);
??????????border-top:?1px?solid?#f2f2f2;
??????????width:?0.5rem;
??????????height:?0px;
????????}
????????&:after?{
??????????content:?"?";
??????????content:?"?";
??????????position:?absolute;
??????????top:?50%;
??????????left:?50%;
??????????transform:?translate(-50%,?-50%)?rotate(-45deg);
??????????border-top:?1px?solid?#f2f2f2;
??????????width:?0.5rem;
??????????height:?0px;
????????}
??????}
??????.warning-icon?{
????????&:before?{
??????????content:?"?";
??????????position:?absolute;
??????????top:?50%;
??????????left:?50%;
??????????transform:?translate(-50%,?-500%)?rotate(90deg);
??????????border-top:?1px?solid?#f2f2f2;
??????????width:?0.27rem;
??????????height:?0px;
????????}
????????&:after?{
??????????content:?"?";
??????????content:?"?";
??????????position:?absolute;
??????????top:?50%;
??????????left:?50%;
??????????transform:?translate(-50%,?250%)?rotate(-45deg);
??????????background:?#f2f2f2;
??????????width:?3px;
??????????border-radius:?50%;
??????????height:?3px;
????????}
??????}
????}
????.msg?{
??????margin-top:?0.18rem;
??????font-size:?0.24rem;
????}
??}
}
.loading-icon?{
??font-size:?0px;
??box-sizing:?border-box;
??width:?0.72rem;
??height:?0.72rem;
??position:?relative;
??span {
????position:?absolute;
????height:?1px;
????left:?50%;
????top:?50%;
????width:?0.18rem;
????animation:?loading-fade-light?1.1s?infinite?linear;
????background:?rgba(255,?255,?255,?0.3);
????transform-origin:?-0.18rem?50%;
????margin-left:?0.18rem;
????&:nth-child(1)?{
??????animation-delay:?0s;
??????transform:?rotate(0deg);
????}
????&:nth-child(2)?{
??????animation-delay:?0.1s;
??????transform:?rotate(30deg);
????}
????&:nth-child(3)?{
??????animation-delay:?0.2s;
??????transform:?rotate(60deg);
????}
????&:nth-child(4)?{
??????animation-delay:?0.3s;
??????transform:?rotate(90deg);
????}
????&:nth-child(5)?{
??????animation-delay:?0.4s;
??????transform:?rotate(120deg);
????}
????&:nth-child(6)?{
??????animation-delay:?0.5s;
??????transform:?rotate(150deg);
????}
????&:nth-child(7)?{
??????animation-delay:?0.6s;
??????transform:?rotate(180deg);
????}
????&:nth-child(8)?{
??????animation-delay:?0.7s;
??????transform:?rotate(210deg);
????}
????&:nth-child(9)?{
??????animation-delay:?0.8s;
??????transform:?rotate(240deg);
????}
????&:nth-child(10)?{
??????animation-delay:?0.9s;
??????transform:?rotate(270deg);
????}
????&:nth-child(11)?{
??????animation-delay:?1s;
??????transform:?rotate(300deg);
????}
????&:nth-child(12)?{
??????animation-delay:?1.1s;
??????transform:?rotate(330deg);
????}
??}
}
@-webkit-keyframes?loading-fade-light?{
??0%?{
????background-color:?#fff;
??}
??100%?{
????background-color:?rgba(255,?255,?255,?0);
??}
}
@keyframes?loading-fade-light?{
??0%?{
????background-color:?#fff;
??}
??100%?{
????background-color:?rgba(255,?255,?255,?0);
??}
}
style>
入口文件注冊:
import?vueToast?from?'@/components/vue-toast'Vue.use(vueToast);
React 插件toast的封裝
Toast/index.js
import?React?from?"react";import?ReactDOM?from?'react-dom';
import?Toast?from?'./toast';
?
export?default?class?Global?{
?static?toastEle='';
?static?toast(option)?{
??var?setting={
???type:0,
????content:"默認信息",
????time:2000,
????opacity:0,
????onSucc:()=>{}
??};
??
??if(typeof?option?=="string"){
???setting={...setting,content:option,type:4}
??}else{
???setting={...setting,...option}
??}
??
??this.show(0,setting);
??
??if(setting.type!==3){???//loading需要手動關閉
???setTimeout(()?=>?{
????this.hide();
????setting.onSucc();
???},?setting.time);
??}
?}
?
?static?dialog(option)?{
???var?setting={
????type:0,
????title:"我是默認title",
????content:"我是默認content",
????btnSucc:"我是默認btn",
????CloseShow:false,
????onClose(){
?????console.log("蒙層回調");
??????},
????onSucc(){
?????console.log("成功回調");
??????},
??????onFail(){
???????console.log("失敗回調");
??????}
???};
???
???setting={...setting,...option};
???
???this.show(1,setting);
?}
???
?
?static?show(n,setting)?{
??
??var?div?=?document.createElement('div');
??var?id?=?document.createAttribute("id");
??
??this.toastEle='pluginEle-'+new?Date().getTime();
??
??id.value?=?this.toastEle;
??div.setAttributeNode(id);
??document.body.appendChild(div);
??ReactDOM.render(<Toast?setting={setting}?/>,?div);
?}
?static?hide()?{
??var?toastEle?=?document.querySelector("#"+this.toastEle);
??if(toastEle){
???ReactDOM.unmountComponentAtNode(toastEle);
??????document.body.removeChild(toastEle);
??}
?}
}
Toast/toast.js
import?React?from?"react";import?'./toast.less'
export?default?class?Toast?extends?React.Component?{
?constructor(props)?{
??super(props);
?}
?checkToast(n)?{
??switch(n)?{
???case?0:
????return?(<div?className="icon"><div?className="success-icon">div>div>)
????break;
???case?1:
????return?(<div?className="icon"><div?className="fail-icon">div>div>)
????break;
??????case?2:
????return?(<div?className="icon"><div?className="warning-icon">div>div>)
????break;
??????case?3:
????return?(
???????????????<div?className="loading-icon"><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span>div>
???????????)
????break;
???default:
???????return?null
??}
?}
?render()?{
??let?{
???type,content,opacity?=?0
??}?=?this.props.setting;
??let?style?=?{
???"background":?`rgba(0,0,0,${opacity})`
??}
??return(
???<div?className="mask"?style={style}><div?className="toast">
???????????{this.checkToast(type)}<div?className="msg">{content}div>div>div>
??);
?}
}
Toast/toast.less
.mask?{????width:?100%;
????height:?100%;
????background:?rgba(0,?0,?0,?0.4);
????position:?fixed;
????left:?0px;
????top:?0px;
????display:?flex;
????justify-content:?center;
????align-items:?center;
????z-index:?10000;
????.toast-msg?{
????????font-size:?24px;
????????text-align:?center;
????????position:?relative;
????????transform:?translateX(-50%);
????????color:?#fff;
????????left:?50%;
????????padding:18px?27px;
????????overflow:?hidden;
????????border-radius:?4px;
????????white-space:?nowrap;
????????display:?block;
????????background:?rgba(0,?0,?0,?0.7);
????}
????.toast?{
????????font-size:?0px;
????????padding:?27px?9px;
????????width:?226px;
????????overflow:?hidden;
????????display:?flex;
????????align-items:?center;
????????flex-direction:?column;
????????color:?#f2f2f2;
????????background:?rgba(51,?51,?51,?0.94);
????????border-radius:?9px;
????????text-align:?center;
????????.icon?{
????????????width:72px;
????????????height:72px;
????????????border-radius:?50%;
????????????border:?1px?solid?#f2f2f2;
????????????position:?relative;
????????????justify-content:?center;
????????????align-items:?center;
????????????display:?flex;
????????????position:?relative;
????????????margin-bottom:?18px;
????????????.success-icon?{
????????????????border-right:?1px?solid?#f2f2f2;
????????????????border-bottom:?1px?solid?#f2f2f2;
????????????????transform:?rotate(45deg);
????????????????width:27px;
????????????????height:?45px;
????????????????margin-top:?-18px;
????????????????
????????????}
????????????.fail-icon?{
????????????????&:before?{
????????????????????content:?"?";
????????????????????position:?absolute;
????????????????????top:?50%;
????????????????????left:?50%;
????????????????????transform:?translate(-50%,?-50%)?rotate(45deg);
????????????????????border-top:?1px?solid?#f2f2f2;
????????????????????width:?50px;
????????????????????height:?0px;
????????????????}
????????????????&:after?{
????????????????????content:?"?";
????????????????????content:?"?";
????????????????????position:?absolute;
????????????????????top:?50%;
????????????????????left:?50%;
????????????????????transform:?translate(-50%,?-50%)?rotate(-45deg);
????????????????????border-top:?1px?solid?#f2f2f2;
????????????????????width:?50px;
????????????????????height:?0px;
????????????????}
????????????}
????????????.warning-icon?{
????????????????&:before?{
????????????????????content:?"";
????????????????????display:?block;
????????????????????position:?absolute;
????????????????????top:?15px;
????????????????????left:?50%;
????????????????????background:#f2f2f2;
????????????????????width:1px;
????????????????????height:?30px;
????????????????}
????????????????&:after?{
????????????????????content:?"";
????????????????????position:?absolute;
????????????????????bottom:?14px;
????????????????????left:?50%;
????????????????????background:#f2f2f2;
????????????????????width:?6px;
????????????????????margin-left:?-2px;
????????????????????border-radius:?50%;
????????????????????height:?6px;
????????????????}
????????????}
????????}
????????.msg?{
????????????
????????????font-size:24px;
????????}
????}
}
.loading-icon?{
????font-size:?0px;
????margin-bottom:?18px;
????box-sizing:?border-box;
????width:?72px;
????height:?72px;
????position:?relative;
????span {
????????position:?absolute;
????????height:?1px;
????????left:?50%;
????????top:?50%;
????????width:?18px;
????????animation:?loading-fade-light?1.1s?infinite?linear;
????????background:?rgba(255,?255,?255,?0.3);
????????transform-origin:?-18px?50%;
????????margin-left:?18px;
????????&:nth-child(1)?{
????????????animation-delay:?0s;
????????????transform:?rotate(0deg);
????????}
????????&:nth-child(2)?{
????????????animation-delay:?0.1s;
????????????transform:?rotate(30deg);
????????}
????????&:nth-child(3)?{
????????????animation-delay:?0.2s;
????????????transform:?rotate(60deg);
????????}
????????&:nth-child(4)?{
????????????animation-delay:?0.3s;
????????????transform:?rotate(90deg);
????????}
????????&:nth-child(5)?{
????????????animation-delay:?0.4s;
????????????transform:?rotate(120deg);
????????}
????????&:nth-child(6)?{
????????????animation-delay:?0.5s;
????????????transform:?rotate(150deg);
????????}
????????&:nth-child(7)?{
????????????animation-delay:?0.6s;
????????????transform:?rotate(180deg);
????????}
????????&:nth-child(8)?{
????????????animation-delay:?0.7s;
????????????transform:?rotate(210deg);
????????}
????????&:nth-child(9)?{
????????????animation-delay:?0.8s;
????????????transform:?rotate(240deg);
????????}
????????&:nth-child(10)?{
????????????animation-delay:?0.9s;
????????????transform:?rotate(270deg);
????????}
????????&:nth-child(11)?{
????????????animation-delay:?1s;
????????????transform:?rotate(300deg);
????????}
????????&:nth-child(12)?{
????????????animation-delay:?1.1s;
????????????transform:?rotate(330deg);
????????}
????}
}
@-webkit-keyframes?loading-fade-light?{
????0%?{
????????background-color:?#fff;
????}
????100%?{
????????background-color:?rgba(255,?255,?255,?0);
????}
}
@keyframes?loading-fade-light?{
????0%?{
????????background-color:?#fff;
????}
????100%?{
????????background-color:?rgba(255,?255,?255,?0);
????}
}
使用
import?$?from?'@/component/Toast/index';...
$.toast({
?type:0,
?content:?"我是默認Toast",
?time:?1000,
?opacity:?.5,
?onSucc()?{
??console.log("我是Toast的回調!")
?}
});
??
$.toast("我是默認Toast");
為什么不掛載在React原型鏈上?
有坑!主要原因還是React組件的this神出鬼沒!
ES6 toast插件
var?body?=?document.body
var?tip
var?timeout
var?time?=?3000
var?setStyleTime?=?50
function?Tip?(str,?time)?{
??if?(tip)?{
????clearTimeout(timeout)
????//?tip.find('p').html(str);
??}?else?{
????tip?=?document.createElement('div')
????tip.className?=?'__toast'
????tip.innerHTML?=?str
????//?tip.style.cssText?=?'z-index:?999;position:?fixed;webkit-transition:?opacity?.3s?ease;transition:?opacity?.3s?ease;opacity:?0;color:?#fff;border-radius:?8px;left:?50%;width:?80%;margin-left:?-40%;?/*px*/text-align:?center;line-height:?1.5;background:?rgba(0,0,0,.6);padding:?1%?1%;top:?45%;box-sizing:?border-box;font-size:?1.5em;';
????body.appendChild(tip)
????setTimeout(function?()?{
??????tip.style.opacity?=?1
????},?setStyleTime)
??}
??timeout?=?clear(time)
}
function?clear?(time)?{
??return?setTimeout(remove,?time)
}
function?remove?()?{
??if?(tip)?{
????body.removeChild(tip)
????tip?=?null
??}
}
function?entry?(msg,?expire)?{
??msg?=?msg?||?''
??if?(!expire?||?expire?<=?setStyleTime)?{
????expire?=?time
??}
??Tip(msg,?expire)
};
export?default?entry
附:React開發技巧
自動注冊全局組件或函數 require.context
我的業務場景大部分是中后臺,雖然封裝和使用了很多第三方組件,但還是免不了需要自己封裝和使用很多業務組件。但每次用的時候還需要手動引入,真的是有些麻煩的。
/**?*?@desc?webpack打包入口文件??
?*?@example?自動引入子目錄下所有js文件
?*/
let?moduleExports?=?{};
const?r?=?require.context('./',?true,?/^\.\/.+\/.+\.js$/);
r.keys().forEach(key?=>?{
????let?attr?=?key.substring(key.lastIndexOf('/')?+?1,?key.lastIndexOf('.'));
????moduleExports[attr]?=?r(key);
});
module.exports?=?moduleExports;
我們其實可以基于 webpack 的require.context來實現自動加載組件并注冊的全局的功能。相關原理在之前的文章中已經闡述過了。具體代碼如下
我們可以創建一個GlobalComponents文件夾,將你想要注冊到全局的組件都放在這個文件夾里,在index.js里面放上如上代碼。之后只要在入口文件main.js中引入即可。
//main.jsimport?'./components/Table/index'?//?自動注冊全局業務組件
這樣我們可以在模板中直接使用這些全局組建了。不需要再繁瑣的手動引入了。
一把梭改變state值
this.setState({???[name]:?value
??});
const?{?data?}?=?this.state;
this.setState({?data:?{...data,?key:?1?}?});
另外一種可以通過callback的方式改變state的值
this.setState(({?data?})?=>?({?data:?{...data,?key:?1?}?}));還可以:
this.setState((state,?props)?=>?{????return?{?counter:?state.counter?+?props.step?};
});
還可以一把梭:
this.state.a=1;this.state.b="張三";
this.state.c=true;
this.state.xxx=...
...
this.setState(this.state);???//一把梭
this.setState支持異步async await
?this.setState((prevState)?=>?({??isFiltered:?!prevState.isFiltered
?}),?()?=>?{
??this.filterData();
?});
?clickMe=(e)=>{
????this.setState((prevState)=>{
??????return?{num:prevState.num+1}
????});
?}
??async?clickMe1(){
????await?this.setState((prevState)=>{
??????return?{num:prevState.num+1}
????});
????await?this.setState((prevState)=>{
??????return?{num:prevState.num+1}
????});
????await?this.setState((prevState)=>{
??????return?{num:prevState.num+1}
????});
??}
唯一key
react數組循環,基本都會設置一個唯一的key,表格的對象數組循環一般沒什么問題,數據基本都會有一個id。那有種情況就比較坑了,出現在表單形式的頁面結構中,對某個數組進行增刪改操作,一般對于非對象數組而言,沒有id,可能很多人會偷懶,循環的時候,直接設置數組的下標index作為key,當出現增刪改時候,就會出現數據對不上或者重新渲染組件的問題等。解決方案有很多種,例如把字符串數組等重組對象數組,每個元素設置一個唯一id等。另外有個方式:推薦使用shortid生成唯一key的數組,和數據數組一起使用,省去提交數據時再重組數組。
import?React?from?'react';import?shortid?from?'shortid';
class?Demo?extends?React.Component?{
????constructor(props)?{
??super(props);
??this.state?=?{
???data:?['a',?'b',?'c']
??}
??this.dataKeys?=?this.state.data.map(v?=>?shortid.generate());
?}
?
????deleteOne?=?index?=>?{?//?刪除操作
????????const?{?data?}?=?this.state;
????????this.setState({?data:?data.filter((v,?i)?=>?i?!==?index)?});
????????this.dataKyes.splice(index,?1);
????}
????
????render()?{
?????return?(
?????????<ul>
???????????????{
???????????????????data.map((v,?i)?=>?<li?onClick={i?=>?this.deleteOne(i)}??
????????????????????????key={this.dataKeys[i]}
????????????????????>
????????????????????????{v}li>
????????????????????)
???????????????}?ul>
?????)
?}
}
//?稍微抽取,可以封裝一個通用的組件
三目運算
通過判斷值是否存在來控制元素是否顯示,一般三目運算可以達到此效果,最簡單的還是用短路的寫法:
//?不錯const?flag?=?'something';
flag?&&?<div>div>
//?很好
//?注意一般可能上面寫法多一些,但當flag為0?的時頁面上會顯示0,用!!將其轉為boolean避免坑,
//?代碼也更規范
const?flag?=?'something';
!!flag?&&?<div>div>
使用組件,傳遞props
const?{?data,?type,?something?}?=?this.state;<Demo?data={data}type={type}something={something}
/>
也許另外一種傳遞方式更簡潔:
const?{?data,?type,?something?}?=?this.state;<Demo?
????{...{?data,?id,?something?}}
/>
簡化props
組件的props有時候會定義很多,但是調用組件傳遞props的時候又想一個個傳,不想一次性傳遞一個option對象,通過擴展運算符和解構賦值可以簡化此操作:
const?Demo?=?({?prop1,?prop2,?prop3,?...restProps?})?=>?(????<div>
????????xxxx
????????{?restProps.something?}div>
)
//?父組件使用Demo
????prop1={xxx}
????prop2={xxx}
????something={xxx}
/>
優化React 性能
React 性能優化有很多種方式,那常見的一種就是在生命周期函數shouldComponentUpdate里面判斷某些值或屬性來控制組件是否重新再次渲染。
判斷一般的字符串,數字或者基礎的對象,數組都還是比較好處理,那嵌套的對象或者數組就比較麻煩了,對于這種,可以轉成字符串處理,但屬性值的位置不同時,那就無效了。
推薦使用lodash(或者其他的類似庫)的isEqual對嵌套數組或對象進行判斷(相比其他方式更簡單些)
shouldComponentUpdate(nextProps,?nextState)?{????if?(_.isEqual(nextState.columns,?this.state.columns))?return?false;
????return?true;
}
創建彈層
創建彈層的三種方式:
1.普通組件通過state和樣式控制,在當前組件中顯示彈層-每次引入組件并且render里面控制顯示,掛載節點在某組件里面
//?彈層?const?Dialog?=?()?=>?<div>彈層div>
//?某組件
render()?{
????return?(
????????this.state.showDialog?&&?<Dialog?/>
????)
}
2.通過Portals創建通道,在根節點外部掛載組件-但還是需要每次引入并且在render里面調用
//?彈層?class?Dialog?extends?React.Component?{
??constructor(props)?{
????super(props);
????this.el?=?document.createElement('div');
??}
??componentDidMount()?{
????modalRoot.appendChild(this.el);
??}
??componentWillUnmount()?{
????modalRoot.removeChild(this.el);
??}
??render()?{
????return?ReactDOM.createPortal(
??????this.props.children?||?<div>xxxxdiv>,
??????this.el,
????);
??}
}
//?某組件
render()?{
????return?(
????????this.state.showDialog?&&?<Dialog?/>
????)
}
3.推薦使用ReactDom.render創建彈層-掛載根節點外層,使用也更方便
//?demolet?dialog;
class?Dialog?{
????show(children)?{????//?顯示
????????this.div?=?document.createElement('div');
????????document.body.appendChild(this.div);
????????ReactDom.render(children?||?<div>xxxxdiv>,?this.div);
????}
????destroy()?{?????//?銷毀
????????ReactDom.unmountComponentAtNode(this.div);
????????this.div.parentNode.removeChild(this.div);
????}
}
export?default?{
????show:?function(children)?{
????????dialog?=?new?Dialog();
????????dialog.show(children);
????},
????hide:?xxxxx
};
//?某組件
import?Dialog?from?'xxx';
alert?=?()?=>?{
????Dialog.show(xxxx);
}
render()?{
????return?(
????????<button?onClick={this.alert}>點擊彈層button>
????)
}
插槽:children
render props是現在很流行的一種渲染方式,通過回調函數,渲染子組件,參數可為父組件的任意屬性值(官網也有相應的介紹)新版的contextApi也采用了這個模式。
很多種場景使用此方式的做法:
//?權限控制組件,只需要封裝一次connect,//?通過render?props向子組件傳遞權限
class?AuthWidget?extends?Component?{
????render()?{
????????return?this.props.children(this.props.auth);
????}
}
const?mapStateToProps?=?state?=>?{
????const?{?auth?}?=?state;
????return?{?auth:?state.auth?};
};
export?default?connect(mapStateToProps)(AuthWidget);
//?其他組件使用
????children={auth?=>?auth.edit?&&?編輯}
/>
//?使用antd的form時
const?Test?=?({?form,?children?})?=>?{
????return?children(form);
};
const?FormTest?=?Form.create()(Test);
class?Demo?extends?Component?{
????render()?{
????????return?(
????????????
????????????????xxxxx
????????????????????{?form?=>?{
????????????????????????this.form?=?form;
????????????????????????return?(
????????????????????????????????????{getFieldDecorator('field',?xxx)(
????????????????????????????????????)}
????????????????????????)
????????????????????}}
????????)
????}
}
子組件改變父組件的state
子組件改變父組件的state方式有很多種,可以在父組件設置一個通用函數,類似:setParentState,通過子組件回調處理時,就可以更方便的統一處理:
//?父組件state?=?{
????data:?{}
}
setParentState?=?obj?=>?{
????this.setState(obj);
}
//?子組件
onClick?=?()?=>?{
????this.props.setParentState({?data:?xxx?});
}
永遠不要直接設置state的值
永遠不要直接設置state的值:this.state.data = { a: 1 }。這個會導致幾個問題: 1:組件不會重新渲染
2:shouldComponentUpdate(nextProps, nextState) 函數里面 this.state的值是已經改變了,和nextState的值相同。
舉個栗子:
//?wrongconst?{?data?}?=?this.state;
data.a?=?1;?????//?等價于this.state.data.a?=?1;
this.setState({?data?});
//?shouldComponentUpdate里面觀察到?this.state?和nextState的值是相同的
//?此時函數里面性能相關的優化是無效的
//?correct??需要用到當前state值的寫法
this.setState(state?=>?({?data:?{...state.data,?a:?1}?}))
總結
以上是生活随笔為你收集整理的的translate插件_知否 ?知否 ?React插件了解一下!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux进阶之路————开机、重启和用
- 下一篇: mysql 5.6.21不能选择安装路径