文章目录
一,组件的使用
1.1组件的声明
有俩种写法
写法一:在components组件中新建Home. js 文件
import React,{Component} from "react";
//声明组件的类
class Home extends Component{
render(){
return <div>我是Home组件</div>
}
}
export default Home;
写法二:在components组件中新建Cart. js 文件
import React from "react";
class Cart extends React.Component {
render() {
return (
<div>我是Cart组件</div>
)
}
}
export default Cart;
1.2挂载组件
先导入组件,在使用组件(与vue的区别就是,不用注册组件)
//引入react对象,import后边的声明:React是整个react对象(当前对象的属性)
import React, { Component } from 'react';
//引入当前组件的的css脚本
import '../assets/css/App.css';
//导入其他组件 (声明 导入 使用)
import Home from "./Home.js"
import Cart from "./Cart.js"
//ES6中的类继承写法
//class声明类 extends继承
class App extends Component {
//render方法值渲染模板界面 有返回值且返回的是一个对象, render 里面的元素只能有一个根节点
render() {
return (
<div className="App">
<span>我是App组件</span>
<Home></Home>
<Cart/>
</div>
);
}
}
//将App组件暴露
export default App;
二,在组件里面声明数据及绑定数据
绑定普通数据,数据,数据元素集合,数据遍历使用map方法,{}绑定数据
注意: 遍历数组 不能使用foreach,因为它没有返回对象不能渲染到界面上,用map映射
import React, { Component } from "react";
//声明组件的类
class Home extends Component {
//绑数据 普通值 数组 对象 枚举对象+元素
constructor() {
super();
this.state = {
msg: "我是Home组件",
arr: [1, 2, 3, 4, 5, 6],
ele: [{
a: <span>1</span>
},
{
a: <span>2</span>
},
{
a: <span>3</span>
}
]
}
}
render() {
return (
<div>
{ this.state.msg }
<span > 遍历数组</span>
<ul> {
this.state.arr.map(function(value, index) {
return (
<li key = { index } > { value } </li>
)
})
}
</ul>
<span> 绑定数组 + 元素集合 </span>
<ul> {
this.state.ele.map(function(value, index) {
return (
<li key = { index } > { value.a } </li>
)
})
} </ul>
</div>
)
}
}
export default Home;
知识补充
constructor( )——构造方法
这是ES6对类的默认方法,通过 new 命令生成对象实例时自动调用该方法。并且该方法是类中必须有的,如果没有显示定义,则会默认添加空的constructor( )方法。
super( ) ——继承
在class方法中,继承是使用 extends 关键字来实现的。子类必须 在 constructor( )调用 super( )方法,否则新建实例时会报错。
报错的原因是:子类是没有自己的 this 对象的,它只能继承自父类的 this 对象,然后对其进行加工,而super( )就是将父类中的this对象继承给子类的。没有 super,子类就得不到 this 对象。
三,在组件中绑定属性
绑定元素属性,元素类名称,元素行内样式
import React, { Component } from "react";
//声明组件的类
class Home extends Component {
//绑数据 普通值 数组 对象 枚举对象+元素
constructor() {
super();
this.state = {
msg: "我是Home组件",
title:"Home",
isadd:"color",
bg:{
width:"3rem",
height:"3rem",
background:"blue"
}
}
}
render() {
return (
<div>
{ this.state.msg }
<span>绑定元素的属性</span>
<div title="Home"></div>
<div title={this.state.title}></div>
<span>绑定元素类名称</span>
<div className="bg"></div>
<div className={this.state.isadd}></div>
<div className={true?this.state.isadd:""}></div>
{/* js里面的for 和 html 元素的for 相同 (for 属性规定 label 与哪个表单元素绑定) htmlFor */}
<label htmlFor="">文本框</label>
{/*
动态绑定行内样式 必须写成对象的形式
style={{width: '3em',height: '3em'}}
值可以做成拼接值
*/}
<div style={{width:"3em",height:"2em",border:"1px solid red"}}></div>
<div style={this.state.bg}></div>
</div>
)
}
}
export default Home;
通过getAttribute获取自定义属性
import React,{Component} from "react"
class Event extends Component {
constructor(props) {
super(props);
this.state = {
msg:"我是Event组件",
};
}
//设置自定义属性
//捕获当前事件作用的对象 IE:event.srcElement firefox:event.target
databtn=(e)=>{
let target =e.srcElement||e.target;
let res=target.getAttribute("data-id");
console.log(res);
}
render() {
return (
<div>
{this.state.msg}
<button data-id="123" onClick={this.databtn}>设置自定义属性</button>
</div>
);
}
}
export default Event;
四,引入图片
引入图片的俩种方式,远程图片,本地图片(包括import导入和require请求俩种)
import React from "react";
//导入本地图片
import image from "../assets/images/t01c38ff1a84f652273.webp.jpg"
class Cart extends React.Component {
constructor(){
super();
this.state={
msg:" 我是Cart组件",
imgsrc:"https://ps.ssl.qhimg.com/sdmt/250_162_100/t01e3556f4e20d58419.webp"
}
}
render() {
return (
<div>
{/* 导入远程图片 必须要有alt属性 */}
<img src={this.state.imgsrc} alt=""/>
{/* 导入本地图片俩种方法 require动态请求服务上的资源*/}
<img src={require("../assets/images/t01c38ff1a84f652273.webp.jpg")} alt=""></img>
{/* import导入本地图片 */}
<img src={image} alt=""/>
</div>
)
}
}
export default Cart;
五,父子组件传值问题
1.父传子
1.1.使用props传值*
import React, { Component } from 'react';
/**父组件 */
export default class Parent extends Component {
state = {
msg: 1
}
render() {
return (
<div onClick={() => this.setState({ msg: this.state.msg + 1 })} >
{/* 子组件 */}
<Child msg={"传递给子组件的消息:" + this.state.msg.toString()} />
</div>
);
}
}
/**子组件 */
class Child extends Component {
// 默认的props 可写可不写
static defaultProps = {
msg: 1
}
render() {
return (
<div>
{/* 通过props传递过来的参数 */}
{this.props.msg}
</div>
)
}
}
1.2.使用context (上下文)
Context
被归类为高级部分(Advanced),属于React的高级API,但官方并不建议在稳定版的App中使用Context。实际上很多优秀的组件都是通过context来实现的,比如antd的主题样式。用好context可以使项目更灵活。
Context
不仅仅适用于父传子,还可以用来作为跨级传递数据,比如父组件传孙子组件。如果要使用props达到这个效果就要层层传递props。 下面看看context实现方式
A:简单使用 (老方法)
import React, { Component } from 'react';
import PropTypes from 'prop-types';
/**父组件 */
export default class Parent extends Component {
state = {
msg: 0
}
// 声明Context属性
static childContextTypes = {
// 数字类型
msg: PropTypes.number,
// 方法
method: PropTypes.func
}
// 返回Context对象,约定好方法
getChildContext() {
return {
msg: this.state.msg,
method: () => "返回来的信息"
}
}
render() {
return (
<div onClick={() => this.setState({ msg: this.state.msg + 1 })} >
{/* 子组件 */}
<Child />
{/* 无状态子组件 */}
<ChildStateLess />
</div>
);
}
}
/**子组件 */
class Child extends Component {
// 声明需要使用的Context属性 必写 不然听过this.context.xxx 取出来的值为undefind
static contextTypes = {
msg: PropTypes.number
}
render() {
return (
<div>
{/* 通过props传递过来的参数 */}
{this.context.msg}
{/* 孙子组件 */}
<GrandsonComponent />
</div>
)
}
}
/**无状态组件 */
const ChildStateLess = (props, context) => {
return (
<div style={{ color: "red" }} >
{context.msg}
</div>
)
}
/**为无状态组件声明需要使用的Context属性 */
ChildStateLess.contextTypes = {
msg: PropTypes.number
}
/**孙子组件 */
class GrandsonComponent extends Component {
// 声明需要使用的Context属性 必写 不然听过this.context.xxx 取出来的值为undefind
static contextTypes = {
msg: PropTypes.number
}
render() {
return (
<div style={{ color: "green" }} >
{/* 通过props传递过来的参数 */}
{this.context.msg}
</div>
)
}
}
B:使用<React. createContext> Api创建
import React from 'react';
const ExampleContext = React.createContext({
msg: 0,
method: () => "method"
});
此ExampleContext通过React.createContext创建,这个Context对象包含两个组件,和。
两个API代替了getChildContext、childContextTypes、contextTypes这些繁琐的api,更符合react的设计理念。
import React, { Component } from 'react';
import PropTypes from 'prop-types';
const ExampleContext = React.createContext('ExampleContext');
class ExampleProvider extends Component {
state = {
msg: 0
}
render() {
return (
<div onClick={() => {
this.setState({ msg: this.state.msg + 1 })
}} >
<ExampleContext.Provider value={{ msg: this.state.msg, method: () => { } }} >
<Child />
<ChildStateLess />
</ExampleContext.Provider>
</div>
);
}
}
/**子组件 */
class Child extends Component {
render() {
return (
<ExampleContext.Consumer>
{
(context) => (
<div>
{/* 通过props传递过来的参数 */}
{context.msg}
{/* 孙子组件 */}
<GrandsonComponent />
</div>
)
}
</ExampleContext.Consumer>
)
}
}
/**无状态组件 */
const ChildStateLess = (props, context) => {
return (
<ExampleContext.Consumer>
{
(context) => (
<div style={{ color: "green" }} >
{/* 通过props传递过来的参数 */}
{context.msg}
{/* 孙子组件 */}
</div>
)
}
</ExampleContext.Consumer>
)
}
/**为无状态组件声明需要使用的Context属性 */
ChildStateLess.contextTypes = {
msg: PropTypes.number
}
/**孙子组件 */
class GrandsonComponent extends Component {
render() {
return (
<ExampleContext.Consumer>
{
(context) => (
<div style={{ color: "red" }} >
{/* 通过props传递过来的参数 */}
{context.msg}
{/* 孙子组件 */}
</div>
)
}
</ExampleContext.Consumer>
)
}
}
export default ExampleProvider;
1.3直接使用context的地方
- 生命周期:
1.componentWillReceiveProps(nextProps, nextContext)
2.shouldComponentUpdate(nextProps, nextState, nextContext)
3.componetWillUpdate(nextProps, nextState, nextContext)
构造函数: constructor(props, context)
2.子传父
子组件的代码:
render() {
return (
<div>
{/*当input的值改变时将子组件的值传给父组件,toFatherValue是父组件一个属性,用来接口子组件的值*/}
<input onChange={(e) => {
this.props.toFatherValue( e.target.value);
}}/>
{/*点击按钮是给父组件传值*/}
<button type="button" onClick={this.props.toFatherValue.bind(this, "我是子组件EventComponet的值")}>向父组件传值</button>
</div>
)
}
父组件代码
render() {
var name = "<span style='color: #FF0000;'>张三</span>";
return (
<div>
{/*父组件接收子组件的值*/}
<EventComponet toFatherValue={this.getChildValue.bind(this)}/>
<div>从父组件接收过来的值:{this.state.childValue}</div>
</div>
)
}
/**
* 获取从子组件传递过来的值
*/
getChildValue(val) {
console.log("getChildValue", val);
this.setState({
childValue:val
})
}
子组件给父组件传值另一种写法
//子组件代码
render() {
return (
<div>
{/*当input的值改变时将子组件的值传给父组件,toFatherValue是父组件一个属性,用来接口子组件的值*/}
<input onChange={this.props.toFatherValue}/>
</div>
)
}
//父组件代码
render() {
return (
<div> {/*父组件接收子组件的值*/}
<EventComponet toFatherValue={this.getChildValue.bind(this)}/>
<div>从父组件接收过来的值:{this.state.childValue}</div>
</div> )
}
/**
* 获取从子组件传递过来的值
*/
getChildValue(e) {
console.log("getChildValue", e.target.value);
this.setState({
childValue:e.target.value
})
}
总结一:
通过target进行通信
所以对应子组件的input框可以有种写法
A:onChange={(e) => {this.props.toFatherValue( e.target.value);}}
改变值的时候触发,通过 e.target.value获取数值,然后传递父组件的toFatherValue
同样父组件的写法
toFatherValue={this.getChildValue.bind(this)}
getChildValue(val) {
console.log("getChildValue", val);
this.setState({
childValue:val
})
}
//代码解释:子组件的值传给父组件,如组件调用本组件的方法,然后获取到值
B:
//子组件
<button type="button" onClick={this.props.toFatherValue.bind(this, "我是子组件EventComponet的值")}>向父组件传值</button>
<div>从父组件接收过来的值:{this.state.childValue}</div>
return (
<div>
{/*父组件接收子组件的值*/}
<EventComponet toFatherValue={this.getChildValue.bind(this)}/>
<div>从父组件接收过来的值:{this.state.childValue}</div>
</div>
)
}
/**
* 获取从子组件传递过来的值
*/
getChildValue(val) {
console.log("getChildValue", val);
this.setState({
childValue:val
})
}
//对于此种事件传值解释:任然是通过传递给对应的事件(加bind是点击的时候触发,)传过去后,通过{this.getChildValue.bind(this)调用本组件的方法,然后下面就可以直接取值了
取值都是通过e.target.value去取值的,这个在子组件或者父组件都可以
**总结:**父写好state
和处理该state
的函数,同时将函数名通过props
属性值的形式传入子,子调用父的函数,同时引起state
变化,子组件要写在父组件之前。
六,react循环遍历问题
1.使用map方法,用es6的语法进行遍历:
render(){
const numbers = [1,2,3,4,5]
return (
<div>
{
numbers.map((item,index)=>{
return (
<div key={index}>value:{item}, index:{index}</div>
)
})
}
</div>
)
}
2.第二种方式,把遍历map的结果赋值给一个变量,在render中引用
render(){
const numbers = [1,2,3,4,5]
const listData = numbers.map((item,index)=>{
return (
<div key={index}>value:{item}, index:{index}</div>
)
})
return (
<div>
{listData}
</div>
)
}
//解释,把每一条数据循环到李斯特里面去,然后把李斯特取出来
3.第三种:把获得到的数据push到数组,在render中引用
render(){
const numbers = [1,2,3,4,5]
const listData = []; // 声明一个变量,存储遍历的模板数据
numbers.forEach((item,index)=>{
listData.push(<div key={index}>value:{item}, index:{index}</div>)
})
return (
<div>
{listData}
</div>
)
}
//解释:每一次变量都把遍历出来的东西push到一个list里面去,最后打印这个list就行
//map结合判断来处理
tags.split(/[,,]/).map(
tag =>
tag.lengthtag.length
tag.length > 0 ? (
<Tag
style={{ marginTop: 10 }}
closable
key={tag}
afterClose={() => this.deleteStaMem(tag, record.id)}
>
{tag}
</Tag>
) : ('')
)
//解释:tag.lengthtag的长度是不是大于0,是的话,就怎么样怎么样,不是就怎么样怎么样
4.forEach
forEach 主要用于修改数组内容,删除元素属性一类
删除元素属性:
newRecord.pnounMem.forEach(item => {
if (item.id.substring(0, 2)==='tp') {
delete item.id;
}
});
let arr = [1, 2];
arr.forEach((item, index) => {
arr.splice(index, 1);
console.log(1); //输出几次?
});
console.log(arr) //?
//上述代码只执行一次,上面代码等于下面的代码
arr.forEach((item, index) => {
arr.splice(index, 1);
console.log(1);
//这里隐性让index自增加1
index++;
});
var arr1 = arr.filter((index) => {
return index !== 1;
});
console.log(arr1); //[2]
更少的代码量,只是得新建一个变量来接受filter方法的返回值。
你说,我这个人就比较倔强,forEach因为index索引无法重置,对于删除数组项真的很困难,那我非要用forEach去做这个功能行不行,当然行,只是我们得让数组反过来遍历:
arr.slice().reverse().forEach(function (item, index, arr1) {
if (item === 1) {
arr.splice(arr1.length - 1 - index, 1);
}
});
console.log(arr);//[2]
let arr = [1, 2, 1],
i = 0,
length = arr.length;
for (; i < length; i++) {
// 删除数组中所有的1
if (arr[i] === 1) {
arr.splice(i, 1);
//重置i,否则i会跳一位
i--;
};
};
console.log(arr);//[2]
修改元素属性:
deleteTagRecord.pnounMem.forEach(item => {
if (item.id === id) {
const newSyn = item.synonyms.replace(`${removedtag},`, '');
Object.assign(item, {
synonyms: newSyn,
});
}
});
// 结果:
// 1, 0, [1, 2, 3, 4]
// 2, 1, [1, 2, 3, 4]
// 3, 2, [1, 2, 3, 4]
// 4, 3, [1, 2, 3, 4]
显而易见,forEach方法中的function回调支持3个参数,第1个是遍历的数组内容;第2个是对应的数组索引,第3个是数组本身。
七,生命周期函数问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dl5AZh7q-1607318644490)(react图片\react生命周期函数.png)]
1.什么是生命周期函数
生命周期函数指在组件运行的某一个时刻会自动调用执行的函数。
initialization(constructor中做页面的props和state的一些配置)
页面初始化的时候执行。
Monuting (组件第一次将被挂载在页面中)
ComponentWillMount
在组件即将被挂载到页面时立刻执行。
render
页面挂载的时候执行。
ComponentDidMount
页面挂载之后执行。
tips:ComponentWillMount
和ComponentDidMount
只会在第一次挂载的时候执行。
Updation(组件发生更新的时候执行主要包含props
和states
的变化)
shouldComponentUpdate
组件被更新之前,它会自动执行,结果返回一个布尔值,如果返回false,则组件不会往下执行。
componentWillUpdate
组件被更新之前,它会自动执行,但是它在shouldComponentUpdate
之后执行,执行的前提条件为shouldComponentUpdate
返回true。
render
数据发生改变,虚拟dom开始更新,页面重新渲染
componentDidUpdate
组件更新完成之后执行
componentWillReceivProps
主要发生在子组件,执行有2个前提:1、一个组件要从父组件接受参数。2、只要父组件的render函数被重新执行了,子组件的这个生命周期函数就会被执行(这个组件第一次存在于父组件中不会执行,只有当它已经存在于父组件中才会执行)。
Unmounting
componentWillUnmount
当这个组件即将被页面中剔除的时候,就会执行。
初始化过程(Initialization)
在consructor()里面初始化Props和State属性。
挂载过程(Mounting)
componentWillMount():在组件即将被挂载到页面的时刻自动执行。
render():将组件挂载到页面。
componentDidMount():组件被挂载到页面之后立即执行。
更新过程(Updating)
componentWillReceiveProps()(已经在16.4的版本中废弃,不推荐使用):
一个组件要从父组件接收参数, 只要父组件的render()函数非首次(如果这个组件第一次存在与父组件中不会执行,如果已经存在于父组件中才会执行)执行了,子组件的这个生命周期函数就会被执行。如果组件没有Props属性则直接跳过
shouldComponentUpdate()(已经在16.4的版本中废弃,不推荐使用)
:组件更行之前检查是否需要更新,注意这个函数要有一个布尔类型返回值,如果返回false,这一部分的生周期 函数将不会继续执行,即无论如何组件都不会更新。利用这个生命周期函数可以强制关闭不需要更新的子组件来提升渲染性能
componentWillUpdate():
组件更新之前。自动执行。但要在shouldComponentUpdate()执行并返回true之后执行。
render():
将组件更新到页面。
componentDidUpdate():
组件更新完成之后立即执行。
移除过程(Unmounting)
componentWillMount():
当组件即将被页面剔除时执行。
注意事项
注意:React中的render()也是生命周期函数,而constructor()并不是生命周期函数。
生命周期函数是针对组件来说的,并非只有父组件才有生命周期函数,是所有组件都有生命周期函数!
除了render()函数,其他的所有生命周期函数都可以不写,也不会报错,但是如果缺少render()函数程序就会报错,因为所有的生命周期函数除了render()函数都是继承自React中内置的。
AJAX请求一般放在componentDidMount()里面。
2.常见生命周期函数
组件将要挂载时触发的函数:componentWillMount
组件挂载完成时触发的函数:componentDidMount
是否要更新数据时触发的函数:shouldComponentUpdate
将要更新数据时触发的函数:componentWillUpdate
数据更新完成时触发的函数:componentDidUpdate
组件将要销毁时触发的函数:componentWillUnmount
组件中才会执行)执行了,子组件的这个生命周期函数就会被执行。如果组件没有Props属性则直接跳过
shouldComponentUpdate()(已经在16.4的版本中废弃,不推荐使用)
:组件更行之前检查是否需要更新,注意这个函数要有一个布尔类型返回值,如果返回false,这一部分的生周期 函数将不会继续执行,即无论如何组件都不会更新。利用这个生命周期函数可以强制关闭不需要更新的子组件来提升渲染性能
componentWillUpdate():
组件更新之前。自动执行。但要在shouldComponentUpdate()执行并返回true之后执行。
render():
将组件更新到页面。
componentDidUpdate():
组件更新完成之后立即执行。
移除过程(Unmounting)
componentWillMount():
当组件即将被页面剔除时执行。
注意事项
注意:React中的render()也是生命周期函数,而constructor()并不是生命周期函数。
生命周期函数是针对组件来说的,并非只有父组件才有生命周期函数,是所有组件都有生命周期函数!
除了render()函数,其他的所有生命周期函数都可以不写,也不会报错,但是如果缺少render()函数程序就会报错,因为所有的生命周期函数除了render()函数都是继承自React中内置的。
AJAX请求一般放在componentDidMount()里面。
2.常见生命周期函数
组件将要挂载时触发的函数:componentWillMount
组件挂载完成时触发的函数:componentDidMount
是否要更新数据时触发的函数:shouldComponentUpdate
将要更新数据时触发的函数:componentWillUpdate
数据更新完成时触发的函数:componentDidUpdate
组件将要销毁时触发的函数:componentWillUnmount
父组件中改变了props传值时触发的函数:componentWillReceiveProps