一、前言及补充内容
????????昨天学习了 初识、构建以及 React 事件的基本用法和一些注意点,我们大概也掌握了 React 框架的语法. 当然其中也落下了几个问题,我就统一放到这篇文章来处理了.
1. 项目的启动报错问题(三种解决方案)
????????昨天在创建完项目之后,运行也是报了错误,困扰了很久,最终找到了这些方法,并且全部可行,希望对你们有所帮助
- 运行的项目路径不对 cd 到创建的项目路径,再运行
恩… 这个,不要小瞧这个错误,在你某些时候分心,忘了或者看别人自动化构建项目运行时,一味的执行命令,却忘了创建完项目,需要 cd 到指定项目文件夹.那样肯定会报错.这个问题,我昨天也碰到过了,第一次创建运行对于新手还是特别需要注意的
正确的步骤: 安装 React 框架 : npm i -g create-react-app 创建项目 : create-react-app 项目名称 (项目名称避免使用中文) 进入创建的项目路径 : cd 项目名字 运行项目 (如果这里运行出错,请看下面解决方案) : npm start
2. 缺少依赖
????????我们创建完项目之后,会在 package.json 配置中的 script 中看到以下代码
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
eact-scripts是create-react-app中的一个核心包一些脚本和工具的默认配置都集成在里面,执行命令 npm run eject 会复制所有依赖文件和相应的依赖(webpack、babel等)到你的项目。是个单向的操作,一旦 eject ,npm run eject的操作是不可逆的
正确的步骤 : 在你创建完项目之后,运行报错,就 输入复制依赖命令 : npm run eject 然后再运行项目 : npm run start
3. webpack 版本不同
????????第三种方法,在昨天的博客中用到了这种方法,并下载了这张图,让你明白具体是怎么回事
为了解决这个 webpack 版本不同的问题,我们在 src 同级目录下创建 .env 文件夹,然后放入一下代码,就可以解决
SKIP_PREFLIGHT_CHECK=true
2. 无法获取 this 值
????????在js中class的方法默认不会绑定this,必须使用this.handleClick并把他传入onClick,否则调用函数时this的值为undefined。解决绑定this的三种方法:
????????1. 构造函数绑定this(推荐)
class Button extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>点我</button>
);
}
}
????????2. 调用的时候绑定this
class Button extends React.Component {
handleClick(){
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick.bind(this)}>点我</button>
);
}
}
????????3. 箭头函数:箭头函数中的this只会固定的指向声明时的this指向
return (
<button onClick={() => this.handleClick()}>点我</button>
);
3. babel 配置
????????我的 babel 配置是在一篇博客上学习的,这里就不在一 一介绍了,你们可以前去他的博客查看学习
网址 : babel 配置教学网址
二、React 父传子
- 父组件提供要传递的state数据
- 给子组件标签添加属性,值为state中的数据
- 子组件通过props接收父组件中传递的数据
????????代码实例 :
class Parent extends React.Component{
state={
lastName:"张三"
}
render(){
return (
<div className="parent">
父组件:<Child name={this.state.lastName}/>
</div>
)
}
}
const Child = (props)=>{
console.log(props)
return (
<div className="child">
<p>子组件,接收到父组件的数据: {props.name}</p>
</div>
)
}
????????运行后查看浏览器 : 
三、React 子传父
- 父组件提供一个回调函数(用于接收数据)
- 将该函数作为属性的值,传递给子组件
- 子组件通过 props 调用回调函数
- 将子组件的数据作为参数传递给回调函数
????????代码实例 :
class Parent extends React.Component{
state = {
parentMsg:""
}
getChildMsg = data =>{
console.log("我收到了子组件中传递过来的数据 :" ,data)
this.setState({
parentMsg:data
})
}
render(){
return (
<div className="parent">
父组件: {this.state.parentMsg}
<Child getMsg={this.getChildMsg}/>
</div>
)
}
}
class Child extends React.Component{
state = {
msg:"下大雨了"
}
handleClick = () =>{
this.props.getMsg(this.state.msg)
}
render(){
return (
<div className="child">
子组件: <button onClick={this.handleClick}>点我,给父组件传递数据</button>
</div>
)
}
}
????????运行后查看浏览器 : 
四、组件通讯
????????将共享状态提升到最近的公共父组件中,由公共组件管理这个状态
公共组件职责 : 1. 提供共享状态 2. 提供操作共享状态的方法 要通讯的子组件 : 只需通过 props 接收状态或操作状态的方法
????????代码实例 :
class Counter extends React.Component{
state = {
count:0
}
xiugai = () =>{
this.setState({
count:this.state.count + 1
})
}
render(){
return (
<div>
<Child count={this.state.count}/>
<Child2 xiugai={this.xiugai}/>
</div>
)
}
}
const Child = (props) =>{
return <h1>计算器 : {props.count}</h1>
}
const Child2 = (props) =>{
return <button onClick={()=>props.xiugai()}>+1</button>
}
????????运行后查看浏览器 : 
五、生命周期
1. 组件生命周期概述
????????意义 : 组件的生命周期有助于理解组件的运行方式,完成更复杂的组件功能、分析组件错误原因等 ????????组件的生命周期 : 组件从被创建到挂载页面中运行,再到组件不用时卸载的过程 ????????生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数 ????????钩子函数的作用 : 为开发人员在不同阶段操作组件提供了时机
2. 生命周期的三个状态
Mounting:已插入真实 DOM Updating:正在被重新渲染 Unmounting:已移出真实 DOM
3. 挂载卸载过程
????????constructor
constructor完成数据的初始化,接受2个参数:props和content,当想在函数内部使用这两个参数,就必须使用super()传入这两个参数 注意:只要使用constructor就必须写super,否则会导致this的指向错误
????????componentWillMount
componentWillMount一般用的比较少,它更多的时在服务端渲染时使用,当前周期代表的时组件已经经历过constructor初始化数据后,但是还未渲染DOM的时候
????????compontntDidMount
组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染
????????componentWillUnmount
这个周期完成组件的卸载和数据的销毁 清除定时器 移除事件监听addEventListener
4. 更新过程
????????componentWillReceiveProps(nextProps)
接收父组件改变后的props 接收一个参数nextProps 对比nextProps和this.props,将nextProps的state为当前组件的state,从而重新渲染
????????shouldComponentUpdate(nextProps, nextState)
主要用于性能优化 可以控制组件的重新渲染的生命周期,因为在react中,setState后,state发生变化,组件重新渲染,这个周期可以return false来阻止组件的更新 父组件的重新渲染会导致其子组件的重新渲染,这个时候我们是不需要所有的子组件都重新渲染,所以在子组件的shouldComponentUpdate中做判断
????????componentWillUpdate(nextProps, nextState)
shouldComponentUpdate返回true以后,组件进行重新渲染的过程,在这个周期同样可以拿到nexeProps和nextState
????????componentDidUpdate(prevProps,prevState)
组件更新完毕后,react在componentDidMount之后,每次重新渲染都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state
????????render
这个周期react会生成一份虚拟DOM树,每次组件更新时,react会通过diff算法比较新旧DOM树,找到最小差异的DOM节点,重新渲染
4. 生命周期图解

六、受控组件
<input
type="text"
value={this.state.value}
onChange={(e) => {
this.setState({
value: e.target.value.toUpperCase(),
});
}}
/>
????????受控组件要绑定一个change事件;每当表单的状态发生变化,都会被写入组件的state中,这种组件在React中被称为受控组件;在受控组件中,组件渲染出的状态与它的value或者checked prop向对应.react通过这种方式消除了组件的局部状态,是的应用的整个状态可控.
????????React受控组件更新state的流程:
1.可以通过初始state中设置表单的默认值; 2.每当表单的值发生变化时,调用onChange事件处理器; 3.事件处理器通过合成事件对象e拿到改变后的状态,并更新应用的state. 4.setState触发视图的重新渲染,完成表单组件值得更新
react中数据是单向流动的.从示例中,我们能看出来表单的数据来源于组件的state,并通过props传入,这也称为单向数据绑定.然后,我们又通过onChange事件处理器将新的表单数据写回到state,完成了双向数据绑定.
七、非受控组件
import React, { Component } from 'react';
class UnControlled extends Component {
handleSubmit = (e) => {
console.log(e);
e.preventDefault();
console.log(this.name.value);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" ref={i => this.name = i} defaultValue="BeiJing" />
<button type="submit">Submit</button>
</form>
);
}
}
export default UnControlled;
如果一个表单组件没有value props(单选按钮和复选按钮对应的是 checked props)时,就可以称为非受控组件;
使用defaultValue和defaultChecked来表示组件的默认状态; 通过 defaultValue和defaultChecked来设置组件的默认值,它仅会被渲染一次,在后续的渲染时并不起作用
八、总结
????????今日这篇博客补充解决了昨天落下的问题,也新学习了组件之间进行通讯、生命周期、受控组件以及非受控组件. 也学习到了新的编程思维语法.今天的学习到此结束,希望对你们有所帮助.我们下期见!
|