React学习笔记(一)

零、初识React

在一个HTML文件中引入reactreact-dom后,可以访问到这两个对象

引入并查看这两个对象1.PNG

引入并查看这两个对象2.PNG

可以看到,React对象中有一些方法,比如我们接下来要学习的creatElement

一、createElement API

React对象中有一个createElement方法,在这个方法中可以定义一个虚拟DOM
第一个参数表示这个虚拟DOM的名称(如div,p,h1等等,也可以是一个组件的名称)
第二个参数表示这个虚拟DOM上一些必要的属性(如id,classname,titile),如果没有则写入null
第三个参数开始为这个虚拟DOM中所有子元素(为虚拟DOM,所以也需要createElement。如果是文本节点可以直接书写而不需要createElement),有多个则直接跟在后面,作为第三第四第五个参数。

let h1 = React.createElement(
        'h1',
        {
            title:'一个标题',
        },
        'the first react dom'
    );
    console.log(h1);

输出的h1变量.PNG

可以看到,输出的变量为一个对象,它就是我们创建出来的虚拟DOM。其中有一些属性以_开头,这是一些内部属性。
type为这个元素的类型,props则是这个元素的一些子元素等等。

  • 1、将虚拟DOM渲染到页面中
    react-dom中的render函数用于将虚拟DOM渲染到页面中。
    接收两个参数:第一参数表示虚拟DOM,第二个参数表示真实DOM容器



    
    Title
    
渲染.PNG

二、组件化

  • 1.使用createClass创建组件(可以直接跳过)
  • 注意:react 16将createClass移除了,使用es6语法,如果必须使用es5创建类的话,请使用create-react-class包
    如果一个虚拟DOM需要被多次复用,则需要将它封装在一个组件内。使用createClass方法。
    createClass方法接收的参数是一个对象,对象中的属性和方法是对组件的说明。其中render方法是将组件中的虚拟dom输出,所以我们将虚拟dom定义在render方法中。
    render方法的返回值是 vetrual dom tree,就是一个组件,组件名称通常第一个字母大写。
let H1 = React.createClass({
        render: function () {
            return React.createElement(
                'h1',
                {
                    title:'一个标题',
                },
                'the first react dom'
            )
        }
    });
console.log(H1); //输出为一个function

此时发现此时得到一个函数,我们需要的是一个虚拟dom,即一个js对象。所以我们调用React.createElements()方法,第一参数为得到的组件函数,没有其他属性和子元素,所以为null,可以直接不写。

let h1 = React.createElement(H1);
ReactDOM.render(h1,document.getElementById('app1'));// 渲染到页面中

在这里我们可以创建多个虚拟DOM分别挂接在不同的页面元素上,这样不同的元素就是不同的组件,互不影响。如果没有使用组件化,需要多次使用的话就是

ReactDOM.render(h1,document.getElementById('app1'));
ReactDOM.render(h1,document.getElementById('app2'));

此时是同一个虚拟DOM的多次挂载
而组件化过后是

let h1 = React.createElement(H1);
ReactDOM.render(h1,document.getElementById('app1'));
let h2 = React.createElement(H1);
ReactDOM.render(h2,document.getElementById('app2'));

此时h1 h2是不同的虚拟DOM,互不影响。

  • 2.使用函数构造组件
function H2() {
    return 

一个胖子

} ReactDOM.render(

, document.getElementById('app'));

  • 3.ES6创建组件
class H2 extends React.component{
        render() {
            return (
                

the first react dom

) } } ReactDOM.render(

,document.getElementById('app'));

  • 3.组件和元素的区别
    在我们使用createElement构造React元素时,我们得到的是一个React元素,而使用类时,我们得到的是一个函数,通过对组件调用ReactDOM.render方法,组件将生成的React元素返回,ReactDOM实现DOM的更新。
    所以我们也可以这么写
function H2() {
   return 

一个胖子

} let element =

; //生成ReactDOM ReactDOM.render(element, document.getElementById('app'));

class H2 extends React.component{
        render() {
            return (
                

the first react dom

) } } let element =

; //生成ReactDOM ReactDOM.render(element,document.getElementById('app'));

注意组件的返回值只能是单个元素,所以如果是多个,我们需要在外层嵌套一个div

三、JSX语法

解决创建一个虚拟DOM成本过高的问题,使用JSX语法可以让我们用书写HTML的方法来书写虚拟DOM元素。需要编译,使用babel。

let H2 = React.createClass({
 render() {
    return ( 
      

the first react dom

{/*注释要写在插值符号即花括号中,并且使用多行注释的符号,否则会被当成文本元素渲染出来*/} {/*在这里类名叫做className 因为JSX其实是JS的外延而非HTML,所以属性都是按照JS的语法来书写的,比如驼峰*/} ) } }); let h2 = (

); ReactDOM.render(h2,document.getElementById('app'));

四、插值符号{}

在插值符号{}中可以写入变量、语句等等。在return的jsx中使用。

五、style样式的设置

为组件内元素添加样式时,必须传递一个对象

class H3 extends React.Component {
        render() {
            return (
                

一个胖子

) } } ReactDOM.render(

,document.getElementById('app'));

传递了一个对象,并且必须放在{}中。
多单词的属性采用驼峰,有CSS3前缀的第一个字母要大写。

六、props属性

props属性用于向组件传递数据,在复用组件时,传递不同的值实现组件的多样化。
在ReactDOM.render中渲染组件时,向组件传递数据

function H2(props) {
   return 

{props.name}

} ReactDOM.render(

,document.getElementById('app'));

 class H2 extends React.Component {
   render() {
       return (
            

{this.props.titleData}

) } } ReactDOM.render(

, document.getElementById('app'));

七、状态State

  • 1.状态与属性十分相似,但是状态是私有的,完全受控于当前组件。需要添加状态的类,需要按照class语法进行声明,然后在constructor中对state进行定义。构造函数是唯一能够初始化 this.state 的地方。
class H2 extends React.Component {
   constructor(props){
       super(props);
       this.state = {
         state1: '1223'
        }
    }
   render() {
        return (
             

{this.state.state1}

) } } ReactDOM.render(

, document.getElementById('app'));

state也不一定要写在contructor里面,可以像下面这样

class H2 extends React.Component {
   state = {
       state1: '1223'
   }
   render() {
        return (
             

{this.state.state1}

) } } ReactDOM.render(

, document.getElementById('app'));

  • 2.状态的更新应该通过this.setState({state1:'newValue'})方法,而不能直接修改this.state.state1
    this.setState方法的参数也可以是一个函数,像下面这样
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment //该函数将接收先前的状态作为第一个参数,将此次更新被应用时的props做为第二个参数:
}));

组件可以选择将其状态作为属性传递给子组件

It is {this.state.date.toLocaleTimeString()}.

这个子组件也可以是自定义的组件


然后子组件在props中得到传递过来的属性,但是子组件并不知道也不关心这个属性是来自父组件的属性、状态’还是用户手动输入。

function FormattedDate(props) {
  return 

It is {props.date.toLocaleTimeString()}.

; }

这通常被称为自顶向下或单向数据流。 任何状态始终由某些特定组件所有,并且从该状态导出的任何数据或 UI 只能影响树中下方的组件。

八、事件处理

React元素也和DOM元素一样可以绑定时间处理函数,也是采用on来绑定,但是要采用驼峰写法

function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

当使用 ES6 class语法来定义一个组件的时候,事件处理器会成为类的一个方法。

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      
    );
  }
}

ReactDOM.render(
  ,
  document.getElementById('root')
);

必须注意JSX 回调函数中的 this,类的方法默认是不会绑定到 this 的。如果你忘记绑定 this.handleClick 并把它传入 onClick, 调用这个函数的时候 this 的值会是 undefined。(也就是说如果你没有使用bind绑定,那么onClick的处理函数里面的this就是undefinde)。
除了上面代码的方法解决,还可以这样

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      
    );
  }
}

ReactDOM.render(
  ,
  document.getElementById('root')
);
class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
  }

  handleClick = ()  => {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      
    );
  }
}

ReactDOM.render(
  ,
  document.getElementById('root')
);

九、列表生成

    let nums = [1,2,3];
    let list = nums.map((item) => {
        return 
  • {item}
  • }); ReactDOM.render(
      {list}
    ,document.getElementById('app'));

    函数组件形式

        function NumList(props) {
            const nums = props.nums;
            const list = nums.map((item) => {
                return 
  • {item}
  • }) return(
      {list}
    ) } const nums = [1,2,3]; ReactDOM.render(,document.getElementById('app'));

    此时有一个问题就是li没有key属性(按道理这里应该会有一个警告,我也不知道为什么我没有...),我们需要为每一个li元素添加一个key。一个元素的key最好是这个元素在列表中拥有的一个独一无二的字符串

     function NumList(props) {
            const nums = props.nums;
            const list = nums.map((item) => {
                return 
  • {item}
  • }) return(
      {list}
    ) } const nums = [1,2,3]; ReactDOM.render(,document.getElementById('app'));

    key会作为给React的提示,但不会传递给组件。如果组件中需要使用和key相同的值,应将其作为属性传递

    const content = posts.map((post) =>
      
    );
    

    这里Post组件可以读出props.id,但是不能读出props.key
    在前面我们声明了一个单独的list变量并将其放在jsx中,其实我们也可直接将map放到jsx中

        function NumList(props) {
            const nums = props.nums;
            return(
                
      {nums.map((item) => { return
    • {item}
    • })}
    ) } const nums = [1,2,3]; ReactDOM.render(,document.getElementById('app'));

    你可能感兴趣的:(React学习笔记(一))