一、实践好文:技术胖-React16免费视频教程(共28集)
文章定位:了解原生组件写法,State数据驱动,JSX语法,调试工具,axios,父子组件传值,生命周期;
-
前置文章及环境搭建:React Native & React & Ant D & Redux
-
突然发现技术胖在掘金上有发文,推荐阅读:掘金最污的 React16.x 图文视频教程
第五节 组件化编程
//1. 删光src下,新建个index.js
import React from "react"
import ReactDOM from 'react-dom'
import App from './App' //引入组件化名称 组件暂时还没选 可通过ReactDom渲染
//public下有个html,里面有root标签,挂载过去
ReactDOM.render(<App />,document.getElementById('root'))
//1. 新建App.js 这个自定义组件要大写开头
import React, {Component} from 'react'
/**
* 2. 定义并声明组件 这句话相当于
* import React from "react"
* const Component = React.Component
*/
//熟悉的jsx.React规范 xml结合js 遇见{}当做就是 遇见<当做html
class App extends Component{
render(){
return (
<div>
Hello JSPang
</div>
)
}
}
//让这个类暴露出去
export default App
第六节 jsx语法
1、 简化js代码
2、 三元运算符
第七节 服务菜单
1、 输入框表单标签
2、 React要求必须在一个组件的最外层进行包裹
3、 引入并使用react的 < Fragment>标签可取代外层div,网站中检查元素即可发现最外层的一套没了。
第八节 响应式数据原理和绑定方法
1、响应式设计-数据驱动【React核心,需要动态比先考虑数据】
- 官方不用直接操作,不用关注dom的create,by id等;
- target:触发事件的元素。有可能是冒泡的元素
- currentTarget : 事件绑定的元素。 2、JSX格式
- JSX中没有括号 UI语法是不允许换行的,有()就可以换行
import React, { Component, Fragment } from 'react'
//声明一个类继承组件
class Xiaojiejie extends Component {
//使用构造函数
constructor(props) {//参数都叫props
super(props)
//state中 定义组件所需要的数据
this.state = {
inputValue: "default",
list: []
}
}
render() { //jsx
return (//
<Fragment> {/* 减少层级 */}
<div>
{/**
* 大括号里放js代码
* value={this.state.inputValue} 进行数据绑定,此时input框无法输入因为没进行事件绑定
* */}
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} /> {/* .bind(this)绑定方法 */}
<button> 增加服务 </button>
</div>
<ul>
<li>炒菜</li>
<li>做饭</li>
</ul>
</Fragment>
)
}
//事件绑定
inputChange(el) { //定义接受一个参数
console.log(el.target.value);//取得打印值
// this.state.inputValue=el.tatget.value //问题1. 直接写会报错 this指向错误,当前为空
//问题2.不能直接等于赋值,得通过setState方法和小程序一样
this.setState({
inputValue: el.target.value
})
}
}
//es6语法暴露组件 让外部引用到
export default Xiaojiejie
第九节 数据驱动
1、es6(js标准语法)拓展运算符
2、onChange和onClick是官方提供的不同方法体
3、有个报错
- <li>循环时没有唯一key值,
import Item from 'antd/es/list/Item';
import React, { Component, Fragment } from 'react'
//声明一个类继承组件
class Xiaojiejie extends Component {
//使用构造函数
constructor(props) {//参数都叫props
super(props)
//state中 定义组件所需要的数据
this.state = {
inputValue: "",
list: ['鱼香肉丝', '香菇滑鸡']
}
}
render() { //jsx
return (//括号换行
<Fragment> {/* 减少层级 */}
<div>
{/**
* 大括号里放js代码
* value={this.state.inputValue} 进行数据绑定,此时input框无法输入因为没进行事件绑定
* */}
<input value={this.state.inputValue} onChange={this.inputChange.bind(this)} /> {/* .bind(this)绑定方法 */}
<button onClick={this.addList.bind(this)}> 增加服务 </button>{/* 绑定事件 */}
</div>
<ul>{/* 改成从state里取数据 JSX用大括号通过this.state.list.mao进行循环 里面要写个return*/}
{
this.state.list.map((Item, index) => {
return <li key={index+Item}>{Item}</li>
})
}
</ul>
</Fragment>
)
}
//事件绑定
inputChange(el) { //定义接受一个参数
console.log(el.target.value);//取得打印值
// this.state.inputValue=el.tatget.value //问题1. 直接写会报错 this指向错误,当前为空
//问题2.不能直接等于赋值,得通过setState方法和小程序一样
this.setState({
inputValue: el.target.value
})
}
//增加服务的按钮响应方法
addList() {
this.setState({/* setState改变数据 */
list: [...this.state.list, this.state.inputValue],/* es6 ...扩展运算符,相当于一个list数组中使用这个语句把原this.state.list取出来值放到前面 */
//如果想清空原输入框
inputValue:''//单引号空字符
})
}
}
//es6语法暴露组件 让外部引用到
export default Xiaojiejie
第10节 对应删除功能
1、 let声明变量
2、局部变量删除规范
//删除单项服务
deleteItem(index) {
console.log(index)
//let声明局部变量
//正常方法
let listChange =this.state.list
listChange.splice(index,1)//从索引项删除一位
this.setState({ //JSX语法要大括号
list:listChange
})
//不用局部变量会怎么样 异常一 能正常操作,但官方不允许 会产生性能障碍
// this.state.list.splice(index,1)
// this.setState({
// list: this.state.list
// })
// 异常一 不能能正常操作
// this.setState({
// list: this.state.list.splice(index,1)
// })
}
第11节 JSX几个坑
1、 JSX注释得注意,用软件快捷键
2、 新建style.css
-
非正式写法:.input{ border:3px solid #ae7000}
-
导包:import './style.css'
-
添加元素:
-
控制台出现异常-类名冲突,引用css中参数名用className
3、解析输入的html标签
- 直接在input框中输入<h2>Test<h2解析/> 不会对应解析出来
- 使用dangerouslySetInnerHTML
<ul>{/* 改成从state里取数据 JSX用大括号通过this.state.list.mao进行循环 里面要写个return*/}
{
this.state.list.map((Item, index) => {
return (
<li
key={index + Item}
/* 删除多加个index标识*/
onClick={this.deleteItem.bind(this, index)}
dangerouslySetInnerHTML={{__html:item}}/* 有两个大括号,红色的明显是jsx语法,里面的大括号表示一个对象 */
>
{/*{Item} 注释掉,标签内使用dangerouslySetInnerHTML声明*/}
</li>
)
})
}
</ul>
第12节 VSCODE快捷键插件
1、 快速代码插件:Simple React Snippets
2、 官网:Simple React Snippets - Visual Studio Marketpla ce
第13节 组件的拆分
- 快捷键 imrc,cc的运用
第14节 父子组件传值
1、父给子传值
-
定义一个传给子组件的属性content,将map中的item值传递给子组件
<XiaojiejieItem content={item} /> -
子组件中,通过content给props赋值即可
return ( //传递的属性 这里填div/li都行 <li>{this.props.content}</li> );
2、子组件向父组件传值
- react不允许子组件直接干预父组件
- 而且之前的delete事件被注释掉了,子组件里写个新的吧
- 和之前类似,写事件,在标签中调用
- 父组件操作
- 类似定义context的写法再定义一个contextIndex传给子,子同样取法,要传给子方法,注意bind(this)其实是有性能问题的,使用构造方法取代
- 原代码
import React, { Component } from 'react'; //imrc
class XiaojiejieItemss extends Component { //cc
render() {
return (
//传递的属性
<li onClick={this.handleClick.bind(this)}>{this.props.content}</li>
);
}
handleClick(){
console.log("free hug"+this.props.contentIndex)
}
}
export default XiaojiejieItemss;
- 更新
//这个其实快速生成的时候会有的 constructor(props){ super(props) this.handleClick=this.handleClick.bind(this)//在构造方法中就绑定 省的循环里蛋疼 }
render() {
return (
//传递的属性
<li>{this.props.content}</li>
);
}
handleClick(){
console.log("free hug"+this.props.contentIndex)
}
- 父组件通过属性传递方法
this.state.list.map((Item, index) => {
return (
// <li
// key={index + Item}
// /* 删除多加个index标识*/
// onClick={this.deleteItem.bind(this, index)}
// dangerouslySetInnerHTML={{__html:Item}}/* 有两个大括号,红色的明显是jsx语法,里面的大括号表示一个对象 */
// >
// {/*{Item} 注释掉,标签内使用dangerouslySetInnerHTML声明*/}
// </li>
<XiaojiejieItemss
key={index + Item}
content={Item}
contentIndex={index}
//再写个属性处理删除事件 该条目的
deleteTarget={this.deleteItem.bind(this)}
/>
)
})
- 子组件通过传递的属性名调用对应方法,参数相同
handleClick(){
//console.log("free hug"+this.props.contentIndex)
this.props.deleteTarget(this.props.ind)
}
第15节 单向数据流
- 之前的方法可以传递参数,方法,当然也可以传递列表;
- 之所以叫单向是因为只能传递不能修改,13节没有修改,删除方法对应调用了父类方法也是由于这个原因;
- 子组件将行改值会报错;
Cannot assign to read only property 'list' of object '#<Object>'
1、和其他前端框架配合使用-例如Jquery
- 这种写法当前只对root进行了渲染,其实public里还有其他控件,比如title等,root中可以写
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<!-- 可以使用jQuery替换 -->
<div style="color: red;">Free hug</div>
第16节 React调试工具
- 之前都是使用console.log 调试太蛋疼了
- Chrome插件:React developer tools
1、 图标状态
- 灰色:页面不是又React编写的。
- 蓝色: 页面是用React编写的,且在生产/Releas环境。
- 红色:页面是用React编写的,且在UAT/debug当中。
第17节 React高级-PropTypes校验传递值
- 虽然组件间传值了,但是没加类型校验,谁知道你传的是啥-PropTypes应运而生
- sample:父组件向子传值,子组件需校验-引入依赖impt;使用defaultProps,父组件不传递属性也不会崩
- 在class外 export之上
XiaojiejieItemss.propTypes={
content:PropTypes.string.isRequired,//必传属性 声明
deleteItem:PropTypes.func,
index:PropTypes.number
}
XiaojiejieItemss.defaultProps={
content:"月海",//必传属性
deleteItem:PropTypes.func,
index:PropTypes.number
}
- 测试连接写法
render() {
return (
//传递的属性
<li onClick={this.handleClick}>
{this.props.content}测试连接-{this.props.content}
</li>
);
}
第18节 ref属性的使用
- 在父组件的input中类似写属性的方式,使用ref穿的value
ref ={input=> {this.input=input}}//es6语法 传递input参数 - 方法里就可以直接取了
// //事件绑定
// inputChange(el) { //定义接受一个参数
// console.log(el.target.value);//取得打印值
// // this.state.inputValue=el.tatget.value //问题1. 直接写会报错 this指向错误,当前为空
// //问题2.不能直接等于赋值,得通过setState方法和小程序一样
// this.setState({
// inputValue: el.target.value
// })
// }
//事件绑定
inputChange() { //定义接受一个参数
this.setState({
inputValue: this.input.value
})
}
- 测试在ul里定义将ul传过去,我超 控件本身传。。然后打length,发现对不上,少一个;因为setState是异步的->虚拟dom渲染;先打出来后,state才改变
<ul ref={(ul)=>{this.ul=ul}}>
//增加服务的按钮响应方法
addList() {
this.setState({/* setState改变数据 */
list: [...this.state.list, this.state.inputValue],/* es6 ...扩展运算符,相当于一个list数组中使用这个语句把原this.state.list取出来值放到前面 */
//如果想清空原输入框
inputValue: ''//单引号空字符
})
console.log(this.ul.querySelectorAll('li').length)//獲取所有元素
}
- 解决异步问题,setState自带类似lambda的回调
//增加服务的按钮响应方法
addList() {
this.setState({/* setState改变数据 */
list: [...this.state.list, this.state.inputValue],/* es6 ...扩展运算符,相当于一个list数组中使用这个语句把原this.state.list取出来值放到前面 */
//如果想清空原输入框
inputValue: ''//单引号空字符
},()=>{//类似lambda的回调
console.log(this.ul.querySelectorAll('li').length)//獲取所有元素
})
}
第19,20,21节 React高级-生命周期讲解
- 生命周期定义:到一定程度会自己执行;
1、Initialization 初始化阶段
- constructor其实是es6的语法,其实不属于生命周期;心里可看做
Initialization阶段,定义属性(props)和状态(state)。
2、Mounting 挂载阶段
- componentWillMount:组件即将被挂载到页面的时刻执行;
- render:页面state或props发生变化时执行;
- Your render method should have a return statement react/require-render-return
- componentDidMount:组件挂载完成时被执行。
3、update 更新阶段
1、 常规阶段
- shouldComponentUpdate:组件更新之前执行,需返回boolea值,若返回false就不往下执行了(render不会执行,页面也不会进行渲染);
- componentWillUpdate:更新前,shouldComponentUpdate函数之后执行,所以shouldComponentUpdate返回false时这个同样不会执行;
- render()进行渲染,类似安卓里的onCreate方法;
- componentDidUpdate:组件更新之后执行,它是组件更新的最后一个环节;
2、 非常规阶段 1.componentWillReceiveProps:子组件接收到父组件传递过来的参数,父组件render函数重新被执行,这个生命周期就会被执行。
- 顶层组件不会执行,因为他未接受任何属性;
- 这个组件第一次存在于Dom中,函数是不会被执行的;(第一次渲染子组件不会执行,第二次会触发render)
- 如果已经存在于Dom中,函数才会被执行;
4、unMounting阶段 解除挂载阶段
- componentWillUnmount 例如sample子组件删除一条列表就会执行
第22节 React生命周期改善React组件性能-超有用
1、目前问题
- 全组件在执行render,父组件输入框变化时,子组件的render也在执行,且子item有几条每次都会刷一次,几百条那不是会爆炸; 2、解决方法:通过shouldComponentUpdate 上面说的Boolean拦截掉
shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean;
- nextProps:变化后的属性;
- nextState:变化后的状态;
- 完成测试搞定,常见的todolist就是要这种性能优化;
第23节 axios数据请求(封装后的ajax)
1、 终端命令:npm install -save axios
npm install xxx: 安装项目到项目目录下,不会将模块依赖写入devDependencies或dependencies。npm install -g xxx:-g将模块安装到全局,具体安装到磁盘哪个位置,要看npm cinfig prefix的位置npm install -save xxx:-save将模块安装到项目目录下,并在package文件的dependencies节点写入依赖(添加依赖后 其他人安装后npm i就可以下载依赖)。(生产环境)npm install -save-dev xxx:-save-dev模块安装到项目目录下,并在package文件的devDependencies节点写入依赖。(devDependencies uat开发模式环境)
2、 post发起请求,链式.then处理回调成功,.catch处理回调失败;这边模拟失败了是因为没有设置请求头等东西;
第24节:React高级-Axios请求EasyMock
1、临时写的接口数据叫 mock
2、登录Easy Mock (mengxuegu.com),并注册相应信息
第25节:使用CSS3实现动画
- CSS通过类名指定样式
- 动画及参数初见
/* 1.5s缓动动画 先慢后快 */
.show{opacity: 1; transition: all 1.5s ease-in;}
第26节 复杂关键帧动画-CSS3的keyframes动画
- @keyframes /* 定义帧动画及帧节点 */
- :后要紧跟 不能加空格
- 动画结束后会停在第一帧,forwards可以解决
- 做不到消除dom,因为是纯前端,不含逻辑,做不动安卓属性动画那样的阶段性执行xxx方法
/*.hide{opacity: 0;transition: all 1.5s ease-in;}*/
/* :后要紧跟 不能加空格 动画结束后会停在第一帧,forwards可以解决*/
.hide{animation:hide-item 2s ease-in forwards;}
/* 定义帧动画及帧节点 */
@keyframes hide-item{
0%{
opacity: 1;
color:aqua;
}
50%{
opacity: 0.5 ;
color:rgb(0, 140, 255);
}
100%{
opacity:0;
color: rgb(144, 15, 230);
}
}
第27节 react-transition-group
官方维护的动画库,感谢React极好的生态
1、 官方指令:npm install react-transition-group --save
- -save会进生产环境
2、 对应Animate.js可引入三种常见库
- Transition
- CSSTransition Css要自己额外导一下:import { CSSTransition } from 'react-transition-group'
- TransitionGroup
3、 Animate.js中使用CSSTransition对Animate单个组件进行动画控制
render() {
return (
<div>
{/* 三元运算符动态改类名 Css通过className指定样式*/}
{/* <div className={this.state.isShow?'show':'hide'}>I am a hedgehog</div> */}
<CSSTransition
in={this.state.isShow}
timeout={2000}
classNames="animate-test"
unmountOnExit
>
<div className={this.state.isShow?'show':'hide'}>I am a hedgehog</div>
</CSSTransition>
<div><button onClick={this.toToggole}>FreeHug</button></div>
</div>
);
}
4、 使用对应组件并基本声明,css可以写对应状态
5、unmountOnExit 可以控制dom 控件不可见时 dom去除/添加 占位,像Gone;
第28节 多Dom动画制作和编辑
1、TransitionGroup就是为了多动画而生的,结合CSSTransition
2、既然是针对Group的,那这次我们改动的目标是Xiaojiejie.js
- ul下的key要写在直属第一层包裹,有CSSTransition时写在CSSTransition里
- timeout时间是react-transition-group定义属性
- key如果写key={index + Item} 点击第一条动画会有异常
<ul ref={(ul) => { this.ul = ul }}>{/* 改成从state里取数据 JSX用大括号通过this.state.list.mao进行循环 里面要写个return*/}
{/* 将循环包裹住*/}
<TransitionGroup>
{
this.state.list.map((Item, index) => {
return (
// <li
// key={index + Item}
// /* 删除多加个index标识*/
// onClick={this.deleteItem.bind(this, index)}
// dangerouslySetInnerHTML={{__html:Item}}/* 有两个大括号,红色的明显是jsx语法,里面的大括号表示一个对象 */
// >
// {/*{Item} 注释掉,标签内使用dangerouslySetInnerHTML声明*/}
// </li>
<CSSTransition
timeout={1000}
classNames="animate-test"
unmountOnExit
key={index + Item}
appear={true}
>
<XiaojiejieItemss
content={Item}
contentIndex={index}
//再写个属性处理删除事件 该条目的
//list={this.state.list}
deleteTarget={this.deleteItem.bind(this)}
/>
</CSSTransition>
)
})
}
</TransitionGroup>
</ul>