React框架
- 官网网址:https://react.docschina.org/
- React 是一个用于构建用户界面的JavaScript库
- 核心专注于视图,目的实现组件化开发
安装react脚手架 npm install create-react-app -g
create-react-app day1 创建文件名day1的react项目
或
npx create-react-app my-app
cd my-app
npm start
特别的更新
- React 从 v16.3 开始,对生命周期进行了渐进式的调整。废弃了一些生命周期方法和添加了一些新的生命周期方法。
Add a new getDerivedStateFromProps() lifecycle and UNSAFE_ aliases for the legacy lifecycles.
Add a new getSnapshotBeforeUpdate() lifecycle.- Hook 是 React v16.8 的新增特性
Add Hooks — a way to use state and other React features without writing a class
REACT是MVC框架
- REACT :MVC :数据是单项的; MVVM: 数据是双向的;
指令
// yarn start 项目开始 yarn bulid 项目打包 yarn eject 暴露webpack配置
认识react
React 的核心库,在每个js中都要导入react;
ReactDOM.render : 将react元素挂载到root的元素上
为什么这里可以直接写js呢;
这叫JSX语法:在react中支持jsx语法,后缀名是jsx的文件;那么可以在这个文件中直接写标签,
那么这个标签就代表了一个react元素;当真正编译这个标签时,其实是一个react元素对象;
浏览器只支持html,css,js文件,不支持后缀名是.jsx的文件,因为在打开浏览器通过babel
已经将jsx编译成了js;
ReactDOM.render(bar, document.querySelector(“#root”));// root元素就是public中index.html
中id为root的元素;
ReactDOM.render
- react元素,将虚拟的DOM对象转成真实的DOM
- 要挂载的真实的DOM元素到root这个根元素中
import React from "react";
import ReactDOM from "react-dom";
// React 的核心库,在每个js中都要导入react;
// ReactDOM.render : 将react元素挂载到root的元素上
// 为什么这里可以直接写js呢;
// 这叫JSX语法:在react中支持jsx语法,后缀名是jsx的文件;那么可以在这个文件中直接写标签,
那么这个标签就代表了一个react元素;当真正编译这个标签时,其实是一个react元素对象;
// 浏览器只支持html,css,js文件,不支持后缀名是.jsx的文件,因为在打开浏览器通过babel
已经将jsx编译成了js;
//let a= <span></span>;
let bar = <div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
//console.log(a);// 对象;虚拟的DOM对象
ReactDOM.render(bar, document.querySelector("#root"));// root元素就是public中index.html
中id为root的元素;
// ReactDOM.render
// 1. react元素,将虚拟的DOM对象转成真实的DOM
// 2. 要挂载的真实的DOM元素到root这个根元素中
ReactDOM
1.react 元素,在JSX中写的标签,
2.只能有一个render函数,将虚拟的DOM元素通过reactDOM.render渲染到根元素root中;如果有多个,那么后面会把前面的覆盖;如果挂载到不同的元素,是没有问题的;如果挂载到同一个元素下,后面将会把前面的覆盖;
3.react元素必须只能有一个根元素;
render(ele,container,callback)
1.ReactDOM是一个对象,里面包含render这个方法,render这个方法时将react元素转成真实的DOM元素,并且把这个真实的DOM元素插入到页面的根元素中;
2.当执行render时,会把根元素找那个所有的元素进行替换;
3. 当把react元素挂载到页面之后才可以获取
4. 在render中第三个参数是回调函数,当真实的DOM挂载完以后,才会执行
5.ReactDOM.render 是同步渲染DOM,当真正挂载完以后才会继续执行下面的代码;
import React from "react";
import ReactDOM from "react-dom";
let foo = <div id="a">
你很好
</div>
// let bar = <div id="b">
// 大家好,才是真的好
// </div>
// 1.react 元素,在JSX中写的标签,
// 2.只能有一个render函数,将虚拟的DOM元素通过reactDOM.render渲染到根元素root中;如果有多个,
那么后面会把前面的覆盖;如果挂载到不同的元素,是没有问题的;如果挂载到同一个元素下,
后面将会把前面的覆盖;
// 3.react元素必须只能有一个根元素;
// render(ele,container,callback)
// 1.ReactDOM是一个对象,里面包含render这个方法,render这个方法时将react元素转成真实的DOM元素,
并且把这个真实的DOM元素插入到页面的根元素中;
// 2.当执行render时,会把根元素找那个所有的元素进行替换;
// 3. 当把react元素挂载到页面之后才可以获取
// 4. 在render中第三个参数是回调函数,当真实的DOM挂载完以后,才会执行
// 5.ReactDOM.render 是同步渲染DOM,当真正挂载完以后才会继续执行下面的代码;
ReactDOM.render(foo,document.querySelector("#root"),function(){
// 当真实的DOM挂载完毕,会触发这个回调函数;
console.log(100);
});
// ReactDOM.render(bar,document.querySelector("#root1"));
// var divs = document.getElementById("a")
// console.log(divs.id);
console.log(ReactDOM)
JSX语法:
- JSX : 将HTML和JS 混合在一起进行编程;
- 通过{}去取值,取得是当前作用域下的值
- 大括号中支持三元运算符以及表达式
- 花括号中如果是null true undefined false 不显示
- 函数和对象的空间地址不能直接作为react的子元素,不能放在{}中,可以放函数的执行结果(不是引用类型值)
- 对象可以放在组件名的行内属性传递
- 大括号中可以直接放入数组,数组的每一项可以是react元素,最后会被一起渲染到页面上
- 不能直接放函数的空间地址,但是可以放函数的执行结果;
- JSX元素不能使用关键字 class==>className for==>htmlFor,行间属性不能直接使用class关键字,在react中有特殊意义;在react元素label使用for属性,把for换成htmlFor
- 在JSX元素中,行间属性style的属性值需要用{{}}包起来,如果样式中有"-",需要将其样式转成驼峰的方式,margin-right==> marginRight style={{backgroundColor:“red”}}
import React from "react";
import ReactDOM from "react-dom";
let obj = { name: "zh" }
// let a = <div>{obj.name}</div>
// let b = <div>{3 > 1 ? "1" : "2"}</div>
// let c = <div>{100 + 100}</div>
function fn(params) {
var num = 101;
return { num };
}
let o = {};
let ary = [<span>=11=</span>, <span>=22=</span>, <span>=33=</span>]
let d = <div>
<div>{obj.name}</div>
<div>{3 > 1 ? "1" : "2"}</div>
<div>{100 + 100}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
<div>{false}</div>
{/* <div>{NaN}</div> */}
{/* <div>{fn()}</div> */}
{/* <div>{o}</div> */}
{/* <div>{ary}</div> */}
<div className="abc" studentclass="a" style={{ backgroundColor: "red" }}>1234</div>
<div className="aaa" up="b" style={{ color: "red" }}> 13</div>
<div>{"abc"}</div>
<label htmlFor="input1">input</label>
<input type="text" id="input1" />
</div>
ReactDOM.render(d, document.querySelector("#root"));
// ReactDOM.render(React.createElement("div",{className:"a"},"13",
React.createElement("span",null,"sk")),document.querySelector("#root"));
react的数据绑定
- 数据绑定: 在react中的数据绑定,需要使用数组的map方法,将数据一一映射成一个react元素,并且需要在每一个react元素上加上key属性,key一般的属性值唯一
import React from "react";
import ReactDOM from "react-dom";
import "./4.less";
// 在react中需要引入css样式;
// import 语法需要放在当前js的最上面;
let ary = [{name:"贾",age:20},{name:"刘",age:21},{name:"文",age:18}];
// let obj={name:"海"};
// let {name}=obj;
// let a = <div>{name}</div>
// 默认配置文件中是不支持less的;
// 在react中的数据绑定,需要使用数组的map方法,将数据一一映射成一个react元素,
并且需要在每一个react元素上加上key属性,key一般的属性值是唯一
let list = <ul>
{ary.map((item,index)=>{
// map: 映射把return出的值进行一一映射
return <li key={item.name}>{item.name}{item.age}</li>
})}
</ul>
ReactDOM.render(list,document.getElementById("root"));
react的createElement
createElement(type)
- 标签类型 2.行间属性 3.子节点(3.文本内容 4.是子节点)
import React from "react";
import ReactDOM from "react-dom";
// let a = <div>
// <span>中国</span>
// </div>// 这是一个react元素,也叫jsx元素;
//
//console.log(a);// 对象:当js解析时,会把这个标签通过React.createElement转成真实的DOM
// createElement(type)
// 1. 标签类型 2.行间属性 3.文本内容 4.是子节点
let a = React.createElement(
"div",
{a:"北京"},
"北",
React.createElement("p",null,"东",React.createElement("span",null,"一"))
);
// let b =<div a="北京">
// 北
// <p>东</p>
// </div>
// JSX语法其实是React.createElement的语法糖;
ReactDOM.render(a,document.getElementById("root"));
jsx/render
// import React from "react";
// let a = React.createElement("div",{a:1},"北京",
React.createElement("span",null,"123"));
// console.log(a);
class Element {
constructor(type, attr, children) {
// 这个里面的this指向当前Element的实例;
// 给Element的实例新增键值对
this.type = type;
this.props = { ...attr, children: children }
}
// 放到了Element的原型上,实例可以调用
render() {
// 把虚拟的DOM转成真实的DOM
// this --> Elment的实例
//
let ele = document.createElement(this.type);
// 循环实例上的props属性
for (let key in this.props) {
if (key !== "children") {
// key : 设置行间属性
// 如果遇到的行间属性是关键字,那么转成对应行间属性
if (key === "className") {
key = "class"
} else if (key === "htmlFor") {
key = "for"
}
ele.setAttribute(key, this.props[key]);
} else {
for (let i = 0; i < this.props.children.length; i++) {
let cur = this.props.children[i];
// 判断cur是否是Element的一个实例;如果是的话,需要再次调用render
方法转成真实的DOM;如果不是Element实例,那么用文本节点接收
let curEle = cur instanceof Element ? cur.render() :
document.createTextNode(cur);
// createTextNode : 把字符串转成文本节点;
ele.appendChild(curEle);
}
}
}
return ele;
}
}
let obj = {
// createElement 从第三个参数开始,都是其子节点,把子节点放在一个数组中;
// createElement 执行会创建一个虚拟的DOM;原型上的不执行
createElement(type, attr, ...children) {
// children : 这是一个数组
// 返回一个Element的实例
// 当执行new Element,consturctor会执行,
return new Element(type, attr, children)
}
};
// 1. render : 1.将虚拟的DOM转成真实的DOM 2.把真实的DOM插入到container容器中
let objDOM = {
// ele : 虚拟的DOM对象
// ele : ele就是Element的一个实例;虚拟的DOM对象
// container: 将要挂载的DOM元素
render(ele, container, callback) {
// ele.render ():将虚拟的DOM转成真实的DOM
container.appendChild(ele.render());
// callback();
}
}
let a = obj.createElement("ul", { a: 100, b: 200, class: "c" }, "465",
obj.createElement("span", null, "东"));// Element的实例;
objDOM.render(a, document.getElementById("root"));
react组件
react中定义组件有两种方式 :1.函数声明 2.类声明
当渲染一个静态的组件结构时,可以采用普通函数创建的组件
组件 : 可复用 可维护;
1.创建组件
2. 组件的名字必须是大写,为了和内置组件区分开
3. 组件每当使用一次,当前组件函数都会执行一次;
4. 当使用组件时,会把行间属性组合成一个对象传给当前组件的第一个参数
5. 如果需要传入一个对象,那么需要对对象进行…展开,然后放入行间属性
import React from "react";
import ReactDOM from "react-dom";
let a = <div></div>;
// 3种执行方式
function Foo(props) {
console.log(props);
return <div>
<span>{props.a}</span>
<span>{props["0"]}</span>
</div>
}
let obj = { a: "你好我好", b: "同学们好" };
let obj1 = { a: [<span>5</span>, <p>5</p>, 666] };
let ary = [<span>55</span>, <p>5</p>, 666];
let day = <div>
<Foo a="你好我好" b="大家好" />
<Foo a="大家好"></Foo>
<Foo {...obj}></Foo>
<Foo {...obj1}></Foo>
<Foo {...ary}></Foo>
</div>
ReactDOM.render(day, document.getElementById("root"));
// ReactDOM.render(<Foo></Foo>, document.getElementById("root"));
// ReactDOM.render(<Foo/>, document.getElementById("root"));
// ReactDOM.render(Foo(), document.getElementById("root"));
class定义组件
让FOO这个类继承React上面的Component
类声明组件
和function声明组件的区别
class类声明是有状态的,有this,还有生命周期;
- this 2. 有状态 3.有生命周期
属性和状态的变化都会影响视图更新
contructor和render都是react组件的一个生命周期钩子函数
先执行constructor 再执行render函数;
如果想在constructor这个钩子函数中获取到行间属性传递过来的数据,可以在constructor传递一个参数接收
如果需要放在当前的实例上,需要在super把这个props传递过去;
react 中定义类必须在原型上放一个render函数;并且这个render函数的返回值,最后会放到根元素;
类组件通过行间属性,可以把数据以对象的方式放在实例props属性上,这个函数下的this指向当前的组件实例
组件每调用一次,那么render 就会执行一次;
import React from "react";
import ReactDOM from "react-dom";
// 让FOO这个类继承React上面的Component
// 类声明组件
// 和function声明组件的区别
// 类声明是有状态的,有this,还有生命周期;
// 属性和状态的变化都会影响视图更新
class Foo extends React.Component {
constructor(props) {
// contructor和render都是react组件的一个生命周期钩子函数
// 先执行constructor 再执行render函数;
// 如果想在constructor这个钩子函数中获取到行间属性传递过来的数据,
可以在constructor传递一个参数接收
// 如果需要放在当前的实例上,需要在super把这个props传递过去;
super();
// props在实例this上
console.log(1);
//console.log(this)// 空间地址;
// 当执行constructor时,实例上默认的props是undefined,后期会往实例props赋值,
但是如果在super传递,那么会将super的值赋值给props,就可以在实例直接获取了
//console.log(this.props);// undefined
}
render() {
// react 中定义类必须在原型上放一个render函数;并且这个render函数的返回值,
最后会放到根元素;
console.log(2);
// 类组件通过行间属性,可以把数据以对象的方式放在实例props属性上,
这个函数下的this指向当前的组件实例
// 组件每调用一次,那么render 就会执行一次;
return <div>{this.props.a}</div>
}
}
let obj = { c: 1, d: 2 };
let a = <div>
<Foo a="100" b="eee"></Foo>
<Foo a="200" {...obj}></Foo>
</div>
ReactDOM.render(a, document.getElementById("root"));
react属性
constructor:不是必须有的,但是render必须有,render必须有return
render 函数里面是一个作用域;可以写正常的代码
toLocaleString 将时间对象转成时间格式字符串
react元素是组件的基本组成单位;
在render中,返回一个唯一的react元素;
组件名字首字母需要大写;
render 将虚拟的DOM渲染成真实的DOM
ReactDOM.render : 只执行了一次;
视图的更新,需要调用ReactDOM.render方法
import React from "react";
import ReactDOM from "react-dom";
class Bar extends React.Component {
constructor() {
// constructor:不是必须有的,但是render必须有,render必须有return
super();
}
render() {
// render 函数里面是一个作用域;可以写正常的代码
let num = 1;
// toLocaleString 将时间对象转成时间格式字符串
return <div>{this.props.date.toLocaleString()}</div>
}
}
let time = new Date();
// react元素时组件的基本组成单位;
// 在render中,返回一个唯一的react元素;
// 组件名字首字母需要大写;
// render 将虚拟的DOM渲染成真实的DOM
let tt = { a: 1 }
let fn=function(){
console.log(1);
}
// 想让视图每隔一秒更新一次
// 如果在行间属性上用大括号取值;
setInterval(() => {
time = new Date();
ReactDOM.render(<Bar date={time} c={tt}></Bar>, document.getElementById("root"));
}, 1000);
// ReactDOM.render(<Bar date={time}></Bar>,document.getElementById("root"));
// ReactDOM.render : 只执行了一次;
// 视图的更新,需要调用ReactDOM.render方法
属性校验
import React, { Component } from "react";
import ReactDOM from "react-dom";
import PropTypes from "prop-types";
class Student extends Component {
static propTypes = {
// 校验属性的方法
age: PropTypes.number,
// name:PropTypes.array
// PropTypes.bool
// PropTypes.func
// PropTypes.number
// PropTypes.object
// PropTypes.string
}
static defaultProps = {
// 定义默认属性,如果行间没有传递,会解析出默认值来;
// 如果传递会解析传递来的值,默认值会被覆盖
age: 100
}
constructor() {
super();
}
render() {
// 传递过来的属性不可以进行修改; 只读
// this.props.age = 100;
return <div>
{this.props.age}
</div>
}
}
ReactDOM.render(<Student age={1} name="hello"></Student>, document.getElementById("root"));
react的事件绑定
元素的事件一般放在当前组件的原型上
事件里面的this是指向undefined;但是一般希望指向组件的实例
如果事件使用箭头函数,那么该函数中的this指向实例
或者通过bind的方法更改当前函数体中的this指向
import React, { Component } from "react";
import ReactDOM from "react-dom";
// function 和 class定义组件:
class Bar extends Component {
constructor() {
super();
}
// add =(e)=> {
// console.log(100);
// console.log(this, e);
// }
add(e) {
// 元素的事件一般放在当前组件的原型上
// this是指向undefined;但是一般希望指向组件的实例
// 如果事件箭头函数,那么该函数中的this指向实例
// 通过bind的方法更改当前函数体中的this指向
console.log(100)
console.log(this)
console.log(e.target)
}
render() {
// this ==> 实例
// 事件绑定:1.on+事件;事件的首字母需要大写 2. 事件放原型
return <div>
<button onClick={this.add.bind(this)}>
按钮
</button>
</div>
}
}
ReactDOM.render(<Bar></Bar>, document.getElementById("root"));
react中state
组件的数据来源有两个地方,一个是props 属性 state :状态
props : 是从组件外面传递过来的
state : 是组件自己私有的
在react中: 数据更新视图
在react只有属性或者state发生改变,才会引发视图的更新;
在react中,想要更新视图,那么需要调用render,调用需要更新状态,通过组件实例setState执行,同时会让render执行,那么视图就可以得到更新
当想多次更改状态时,更改状态会发生合并;后面一次会把前面那一次覆盖掉;
this.setState({num:this.state.num+1});
add = (val) => {
this.setState((prevState) => {
// prveState : 代表上一次的状态;为了防止更新状态发生合并,这个时候可以使用函数的写法;
// 当前的状态依赖上一次状态的时候,使用函数
// 这个函数的返回值就会覆盖原有的state
return { num: prevState.num + 1 }
});
}
render() {
console.log(100);
return
{/* 如果需要传参,需要在事件外层套一个函数, /}
{this.state.num}
{/ <button onClick={()=>{this.add(2)}}>新增 /}
{/ 因为bind默认返回一个函数,并且已经准备好了参数 */}
<button onClick={this.add.bind(null, 2)}>按钮
}
import React, { Component } from "react";
import ReactDOM from "react-dom";
// 组件的数据来源有两个地方,一个是props 属性 state :状态
// props : 是从组件外面传递过来的
// state : 是组件自己私有的
// 在react中: 数据更新视图
// 在react只有属性或者state发生改变,才会引发视图的更新;
class Bar extends Component {
constructor() {
super();
this.state = { num: 100, a: 999 }// 初始化该组件的状态
}
add = (val) => {
// this.state.num=101;
// console.log(this);
// 在react中,想要更新视图,那么需要调用render,调用需要更新状态,通过组件实例setState执行,同时会让render执行,那么视图就可以得到更新
// 当想多次更改状态时,更改状态会发生合并;后面一次会把前面那一次覆盖掉;
// this.setState({num:this.state.num+1});
// this.setState({num:this.state.num+2});
this.setState((prevState) => {
// prveState : 代表上一次的状态;为了防止更新状态发生合并,这个时候可以使用函数的写法;
// 当前的状态依赖上一次状态的时候,使用函数
// 这个函数的返回值就会覆盖原有的state
return { num: prevState.num + 1 }
});
this.setState((prevState) => {
// 这个函数的返回值就会覆盖原有的state
return { num: prevState.num + 1 }
})
}
render() {
console.log(100);
return <div>
{/* 如果需要传参,需要在事件外层套一个函数, */}
<p>{this.state.num}</p>
<p>{this.state.a}</p>
{/* <button onClick={()=>{this.add(2)}}>新增</button> */}
{/* 因为bind默认返回一个函数,并且已经准备好了参数 */}
<button onClick={this.add.bind(null, 2)}>按钮</button>
</div>
}
}
ReactDOM.render(<Bar></Bar>, document.getElementById("root"));
setState的同异步
this.setState({num:1})
如果有多个状态同时更新,那么setState会发生合并;
this.setState(prevState=>({num:prevState.num+1}));
如果是函数就不再合并了> ;
当下一次的状态依赖上一次的状态时,需要用函数的方法;
setState 是有时候异步的有时候是同步的
1.在react的事件绑定中或react生命后期钩子函数中,调用了setState更改数据,但是这个setState 是异步;
2.在定时器的延时回调中的setState 是同步更新数据的;
import React from "react";
import ReactDOM from "react-dom";
class Bar extends React.Component{
constructor(props){
super(props);
this.state={num:1}
}
add=()=>{
// setState需要将最新的状态传给实例的状态才会引发render执行,不传参,render不会调用;
如果setState传递的值上一次和这一次样,同样会调用render方法;
// this.setState({num:1})
// this.setState({num:1})
// 如果有多个状态同时更新,那么setState会发生合并;
//this.setState(prevState=>({num:prevState.num+1}));
// 如果是函数就不再合并了;
// 当下一次的状态依赖上一次的状态时,需要用函数的方法;
//setState(prevState=>({num:prevState.num+1}));
// setState 是有时候异步的有时候是同步的
// 1.在react的事件绑定中或react生命后期钩子函数中,调用了setState更改数据,
但是这个setState 是异步;
// 2.在定时器的延时回调中的setState 是同步更新数据的;
// this.setState({num:this.state.num+1});
// console.log(this.state.num); //
this.setState({num:this.state.num+1});
this.setState({num:this.state.num+1});
// setTimeout(()=>{
// this.setState({num:this.state.num+1});
// this.setState({num:this.state.num+1});
// console.log(this.state.num); //
// },2000)
}
render(){
//console.log(199);
return <div>
<p>{this.state.num}</p>
<button onClick={this.add}>增加</button>
</div>
}
}
ReactDOM.render(<Bar a="100"></Bar>,document.getElementById("root"));
父子组件
父子组件:将父组件中的数据或状态以行间属性的方式传递给子组件,那么子组件可以通过实例的props
属性拿到父组件的数据
import React from "react";
import ReactDOM from "react-dom";
class Parent extends React.Component{
constructor(){
super();
// 对于parent组件来说,这个state是私有的;
this.state={time:"十二点"}
}
// {} : 如果行间属性是可以放对象的
// 但是元素里面的{}不能直接放对象
render(){
// this ==> 组件实例
return <div>
<p>中午几点吃饭啊</p>
<Child date={this.state}></Child>
</div>
}
}
// 父子组件:将父组件中的数据或状态以行间属性的方式传递给子组件,那么子组件可以通过实例的props
属性拿到父组件的数据
class Child extends React.Component{
constructor(props){
super(props);
console.log(this.props.date);
}
render(){
return <div>
<p>{this.props.date.time}</p>
</div>
}
}
ReactDOM.render(<Parent></Parent>,document.getElementById("root"));
子传父
父组件的数据儿子不能直接改,父组件自己可以改变自己的数据,所以需要将改变数据的方法传给子组件,当执行子组件的方法时,触发父组件的方法进行更新;
this.state = { time: “十二点”, color: “红色” }
color 对于父组件来说是状态;对于子组件来说是属性;
当组件的状态或属性发生改变时,会引发视图的更新;
从父组件传递过来的叫属性,属性是不能更改的;
this.props.bg=“黑色”;
import React from "react";
import ReactDOM from "react-dom";
class Parent extends React.Component {
constructor() {
super();
// 对于parent组件来说,这个state是私有的;
this.state = { time: "十二点", color: "红色" }
// color 对于父组件来说是状态;对于子组件来说是属性;
// 当组件的状态或属性发生改变时,会引发视图的更新;
}
changeBg = () => {
this.setState({ color: "黑色" });
}
render() {
return <div>
<p>中午几点吃饭啊</p>
<Child date={this.state.time} bg={this.state.color} chan={this.changeBg}>
</Child>
</div>
}
}
// 父组件的数据儿子不能直接改,父组件自己可以改变自己的数据,所以需要将改变数据的方法传给子组件,
当执行子组件的方法时,触发父组件的方法进行更新;
class Child extends React.Component {
constructor(props) {
super(props);
console.log(this.props.date);
}
change = () => {
// 从父组件传递过来的叫属性,属性是不能更改的;
// this.props.bg="黑色";
this.props.chan();
}
render() {
return <div>
<p>{this.props.date}</p>
<p>{this.props.bg}</p>
<button onClick={this.change}>改变</button>
</div>
}
}
// let obj = {
// f:()=>{
// console.log(this);
// }
// }
// obj.f();
ReactDOM.render(<Parent></Parent>, document.getElementById("root"));
受控组件
受控组件: 受状态控制的组件
表单类的元素受状态值控制,那么这就是一个受控组件
受控组件:受状态控制,不能直接修改
如果需要修改input的value,需要更改state;那么input就会跟着发生改变
获取到事件对象的value值,对state中的num重新赋值
绑定时没有小括号,那么默认会传递事件对象,如果有小括号,那么事件对象需要单独传递过去
import React from "react";
import ReactDOM from "react-dom";
// 受控组件: 受状态控制的组件
// 表单类的元素受状态值控制,那么这就是一个受控组件
// 受控组件:受状态控制,不能直接修改
class Panel extends React.Component {
constructor() {
super();
this.state = { num: 100, a: 200 }
}
change = (key, e) => {
console.log(key, e);
// 如果需要修改input的value,需要更改state;那么input就会跟着发生改变
// 获取到事件对象的value值,对state中的num重新赋值
// 属性名放了一个变量
//this.setState({[key]:e.target.value})
}
render() {
return <div>
<p>{this.state.num}</p>
{/* 希望把状态的值放到input框中 */}
<input type="text" value={this.state.num} onChange={(e) =>
{ this.change("num", e) }}></input>
<input type="text" value={this.state.a} onChange={(e) =>
{ this.change("a", e) }}></input>
{/* 绑定时没有小括号,那么默认会传递事件对象,如果有小括号,
那么事件对象需要单独传递过去 */}
<input type="text" onChange={() => { this.change(1) }}></input>
</div>
}
}
ReactDOM.render(<Panel></Panel>, document.getElementById("root"));
非受控组件
非受控组件: 不受状态控制的组件
如果给组件行间属性加上一个ref属性,那么会把该元素放在组件实例的refs这个属性上
ref :字符串或函数;如果是函数,会默认将此元素传递给当前函数的参数
import React from "react";
import ReactDOM from "react-dom";
// 非受控组件: 不受状态控制的组件
class Sum extends React.Component {
constructor() {
super();
this.state = { result: "" }
}
add = () => {
// 获取到
// 如果给组件行间属性加上一个ref属性,那么会把该元素放在组件实例的refs这个属性上
// ref :字符串或函数;如果是函数,会默认将此元素传递给当前函数的参数
//console.log(this.refs);
let result = Number(this.refs.a.value) + Number(this.b.value);
this.setState({ result })
}
render() {
return <div>
<input type="text" onChange={this.add} ref="a"></input>+
{/* x这个参数就是当前的元素 */}
<input type="text" onChange={this.add} ref={(x) => {
this.b = x
}}
></input>={this.state.result}
</div>
}
}
ReactDOM.render(<Sum></Sum>, document.getElementById("root"));