一.细节
React的核心思想就是组件化思想,页面会被切分成一些独立的、可复用的组件。
1.React中state和props分别是什么?
props理解为从外部传入组件内部的数据。由于React是单向数据流,所以props基本上也就是从服父级组件向子组件传递的数据。
一种:跳转页面
父组件addressList:item 是参数对象
this.props.history.push('/addAddress');
this.props.routerJump(item,'/addAddress');
const mapDispatchToProps = (dispatch) => {
return {
routerJump: (data,newpathname) => {
dispatch({
type: 'globals/pageJump',
payload: {
goodData: data,
newpathname:newpathname
}
})
},
}
}
export default connect(null,mapDispatchToProps)(AddressList);
子组件addAddress:
const mapStateToProps = ({globals}) =>{
return {
goodData: globals.goodData
}
}
export default connect(mapStateToProps,null)(AddAddressWrapper);
const {goodData} = this.props;
console.log(goodData) //就是父组件传下来的参数
二种:直接传值
父组件addressList:this.state.item 是参数对象
<AddAddress goodData={this.state.item} />
子组件AddAddress:
const {goodData} = this.props;
console.log(goodData) //就是父组件传下来的参数
state
的主要作用是用于组件保存、控制以及修改自己的状态,它只能在constructor
中初始化,它算是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的this.setState
来修改,修改state
属性会导致组件的重新渲染。
constructor(props) {
super(props);
this.state = {
Vaddress:'',
VdoorNum:'',
Vusername:'',
Vdate: now,
};
}
componentDidMount(){
//1.修改state的值
this.setState({Vusername:'王晓燕'})
}
//2.访问state的值
<p>{this.state.Vusername}</p>
区别
state
是组件自己管理数据,控制自己的状态,可变;props
是外部传入的数据参数,不可变;- 没有
state
的叫做无状态组件,有state
的叫做有状态组件; - 多用
props
,少用state
。也就是多写无状态组件。
2.express开启web服务整体流程
3.React-router4 也就是react-router-dom的一切组件的使用
/*
1.withRouter可以包装任何自定义组件,将react-router 的 history,location,match 三个对象传入
2.Authroute是组件
*/
Authroute = withRouter(Authroute);
export default Authroute
4. react-redux的connect
/*
1.Dashboard是组件
2.mapStateToProps 是state的值
const mapStateToProps = (state) =>{
return {users:state.auth}
}
3.logout 是redux的action
*/
Dashboard = connect(mapStateToProps,{logout})(Dashboard);
export default Dashboard;
5. 组件属性类型检测 prop-types
static propTypes = {
name: PropTypes.string.isRequired,//检测字符串
age:PropTypes.number.isRequired,//检测数字
user:PropTypes.object.isRequired,//检测对象
num:PropTypes.array.isRequired,//检测数组类型
bool:PropTypes.bool.isRequired//检测布尔类型
fu: PropTypes.func.isRequired,//检测函数(Function类型)
Symbol: PropTypes.symbol.isRequired//ES6新增的symbol类型
}
二.解决问题
1.react 修改state
一种:简单的修改
constructor(props) {
super(props);
this.state = {
Vaddress:'',
VdoorNum:'',
};
}
componentDidMount(){
this.setState({
Vaddress:'福建省'
});
}
二种:修改state的某个对象所有值
constructor(props) {
super(props);
this.state = {
isbool:false,
addressDate:{
Vaddress:'',
VdoorNum:'',
Vusername:'',
Vdate: now,
Vsex: 0,
Vtel:''
}
};
}
componentDidMount(){
const {goodData} = this.props;//这个是父组件穿过
if(goodData != ''){
this.setState({
addressDate:goodDatas
});
}
console.log(this.state)
}
//输出
{
addressDate:{
Vaddress:"福建省福州市闽侯县"
Vdate:"20018-09-13"
VdoorNum:" 111号"
Vsex:0
Vtel:"18830923940"
Vusername:"小李子"
index:11111
},
isbool:false,
}
三种:修改state的对象中的某一个属性值
constructor(props) {
super(props);
this.state = {
isbool:false,
addressDate:{
Vaddress:'',
VdoorNum:'',
Vusername:'',
Vdate: now,
Vsex: 0,
Vtel:''
}
};
}
componentDidMount(){
let goodDatas = Object.assign({},this.state.addressDate,{Vaddress:'福建省福州市闽侯县'})
this.setState({
addressDate:goodDatas
});
console.log(this.state)
}
//输出
{
addressDate:{
Vaddress:"福建省福州市闽侯县"
VdoorNum:'',
Vusername:'',
Vdate: now,
Vsex: 0,
Vtel:''
},
isbool:false,
}
2.React的onClick函数如何传参
通过bind(this,参数)的方法就可以在onClick中传参了
<Button onClick={this.showEdit.bind(this, 'add')}>添加用户</Button>
showEdit = (type) => {
console.log(type) // 这里面的type就是'add'
this.setState({ modalType: type, modalVisible: true })
};
3.react动态添加class
1.动态的添加class
当前元素上没有其他的class
<div class={'className'}></div>
当前元素上本身有其他的class,又要动态的添加class时:
<div class={['className1',index==0?'className2':null].join(' ')}></div>
或者使用es6中的写法
<div class={`className1 index==0?'className2':null`}></div>
2.动态的添加style样式
<div style={{display:(index==0)?"none":"block"}}></div>
//添加多个样式
<div style={{display:(index==0)?"none":"block","color":"red"}}></div>
dva 中:添加class
1.添加class
this.state={
isStyle:true
}
<div className={this.state.isStyle?styles.tabsByStyle:null}>
2.添加style 样式
this.state={
tabsByStyle:{
"position": "fixed",
"top": "0px",
"zIndex": "9999",
"marginBottom": "0.8rem"
}
}
<div style={this.state.tabsByStyle}>
还可以引用import classnames from 'classnames'
import classnames from 'classnames'
const nameI = "anticon anticon-user";
<i className={classnames({ [`${nameI}`]: true })}>
4.监听滚动事件
componentDidMount () {
window.addEventListener( 'scroll', () => {
let scrollTop = document.documentElement.scrollTop;
if( scrollTop > 76){
this.setState({
isStyle: true,
});
}else{
this.setState({
isStyle: false,
});
}
})
}
<div className={this.state.isStyle?styles.tabsByStyle:null} />
//上面的意思是 当滚动76的时候 添加tabsByStyle类
5.获取验证码倒计时
class Login extends PureComponent {
constructor(props) {
super(props);
this.state = {
'count': 60, // 秒数初始化为60秒
'codeLiked':true // 文案默认为‘获取验证码‘
};
}
//获取短信验证码
handleClick = () =>{
if(this.state.usertel == ' '){
Toast.info('请输入手机号码!', 2);
}else{
console.log(this.state.codeLiked)
// codeLiked is false 的时候,不允许再点击
if (!this.state.codeLiked) {
return
}
let count = this.state.count;
const timer = setInterval(() => {
this.setState({count: (count--)},() => {
if (count === 0) {
clearInterval(timer);
this.setState({
codeLiked: true,
count: 60
})
}else{
this.setState({
codeLiked: false,
count:count
})
}
});
}, 1000);
}
}
render() {
return (
<span onClick={this.handleClick}>
{
this.state.codeLiked?'获取验证码':(this.state.count + 's')
}
</span>
);
}
}
6.React直接渲染从后台传过来的标签
<div dangerouslySetInnerHTML={{__html: "<p>明天会更好!</p>"}} />
constructor(props) {
super(props);
this.state ={
html:'<p>明天hi更好</p>'
}
}
<div dangerouslySetInnerHTML={{__html:this.state.html}}></div>
// oData.info.info 后端返回的数据
<div className={styles.articlePageInfo} dangerouslySetInnerHTML={{__html: `${oData.info.info}`}}>
三.错误
(1).setSate的问题
1.Unhandled Rejection (TypeError): Cannot read property 'setState' of undefined
class Login extends React.Component {
constructor(props){
super(props);
//在组件初始化可以直接操作this.state
this.state={
Odata:{}
}
}
componentDidMount(){
console.log('组件加载完毕!')
axios.get("/data").then(function(res){
if(res.status === 200 ){
console.log(res.data)
this.setState({
Odata:res.data
})
}
})
}
}
上面的代码导致报错,因为this
有2种解决方式:
const that =this;
class Login extends React.Component {
constructor(props){
super(props);
//在组件初始化可以直接操作this.state
this.state={
Odata:{}
}
}
componentDidMount(){
console.log('组件加载完毕!')
const that = this ;
axios.get("/data").then(function(res){
if(res.status === 200 ){
that.setState({
Odata:res.data
})
}
})
}
}
另一种是用箭头函数:
class Login extends React.Component {
constructor(props){
super(props);
//在组件初始化可以直接操作this.state
this.state={
Odata:{}
}
}
componentDidMount(){
console.log('组件加载完毕!')
axios.get("/data").then((res)=>{
if(res.status === 200 ){
this.setState({
Odata:res.data
})
}
})
}
}
2.Cannot read property ‘setState’ of null
constructor(props) {
super(props);
/*关键就是这里,把要使用this的函数 在构造函数中用bind方法传入this*/
this.startFu = this.startFu.bind(this);
this.state = {
data:{}
};
}
startFu(){
this.setState({data:res.data})
}
绑定this就可以
3.Cannot read property 'push' of undefined react
问题:在子组件使用history跳转时失败
this.props.history.push('/detailInfo'); 就报报错
原因:
Router 组件的后代里头才没有 this.props.history ,所以子组件没有push这个函数。
解决方法:
在父组件传递:history={this.props.history}/
<ListInfo ListData={this.state.ListData} history={this.props.history}/>
4.this.setState is not a function
问题:在函数里面执行this,setState
setTimeout(function(){
this.setState({
[key]: false
});
},100);
解决方式是改成箭头函数
setTimeout(() => {
this.setState({
[key]: false
});
},100);