React基础

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

  1. react元素,将虚拟的DOM对象转成真实的DOM
  2. 要挂载的真实的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 混合在一起进行编程;
  1. 通过{}去取值,取得是当前作用域下的值
  2. 大括号中支持三元运算符以及表达式
  3. 花括号中如果是null true undefined false 不显示
  4. 函数和对象的空间地址不能直接作为react的子元素,不能放在{}中,可以放函数的执行结果(不是引用类型值)
  5. 对象可以放在组件名的行内属性传递
  6. 大括号中可以直接放入数组,数组的每一项可以是react元素,最后会被一起渲染到页面上
  7. 不能直接放函数的空间地址,但是可以放函数的执行结果;
  8. JSX元素不能使用关键字 class==>className for==>htmlFor,行间属性不能直接使用class关键字,在react中有特殊意义;在react元素label使用for属性,把for换成htmlFor
  9. 在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)

  1. 标签类型 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,还有生命周期;

  1. 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"));
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值