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容器
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <div id="app"></div>
</head>
<body>
</body>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script>
    console.log(React);
    console.log(ReactDOM);
    let h1 = React.createElement(
        'h1',
        {
            title:'一个标题',
        },
        'the first react dom'
    );
    console.log(h1);
    ReactDOM.render(h1,document.getElementById('app'));
</script>
</html>
渲染.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 <h1 style={{color: 'red', fontSize: '14px', WebkitBoxShadow: '10px 10px yellow'}}>一个胖子</h1>
}
ReactDOM.render(<H2/>, document.getElementById('app'));
  • 3.ES6创建组件
class H2 extends React.component{
        render() {
            return (
                <h1 title='一个标题'>the first react dom</h1>
            )
        }
    }
ReactDOM.render(<H2 />,document.getElementById('app'));
  • 3.组件和元素的区别
    在我们使用createElement构造React元素时,我们得到的是一个React元素,而使用类时,我们得到的是一个函数,通过对组件调用ReactDOM.render方法,组件将生成的React元素返回,ReactDOM实现DOM的更新。
    所以我们也可以这么写
function H2() {
   return <h1 style={{color: 'red', fontSize: '14px', WebkitBoxShadow: '10px 10px yellow'}}>一个胖子</h1>
 }
let element = <H2 />; //生成ReactDOM
ReactDOM.render(element, document.getElementById('app'));
class H2 extends React.component{
        render() {
            return (
                <h1 title='一个标题'>the first react dom</h1>
            )
        }
    }
let element = <H2 />; //生成ReactDOM
ReactDOM.render(element,document.getElementById('app'));

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

三、JSX语法

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

let H2 = React.createClass({
 render() {
    return ( 
      <h1 title='一个标题' className='title'>the first react dom</h1>
     {/*注释要写在插值符号即花括号中,并且使用多行注释的符号,否则会被当成文本元素渲染出来*/}
    {/*在这里类名叫做className 因为JSX其实是JS的外延而非HTML,所以属性都是按照JS的语法来书写的,比如驼峰*/}
    )
  }
});

let h2 = (<H2 />);
ReactDOM.render(h2,document.getElementById('app'));

四、插值符号{}

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

五、style样式的设置

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

class H3 extends React.Component {
        render() {
            return (
                <h1 style={{color:'red',fontSize:'14px',WebkitBoxShadow:'10px 10px yellow'}}>一个胖子</h1>
            )
        }
    }
    ReactDOM.render(<H3 />,document.getElementById('app'));

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

六、props属性

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

function H2(props) {
   return <h1>{props.name}</h1>
}
ReactDOM.render(<H2 />,document.getElementById('app'));
 class H2 extends React.Component {
   render() {
       return (
            <h1 title='一个标题'>{this.props.titleData}</h1>
        )
   }
}
ReactDOM.render(<H2 titleData="the data of user"/>, 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 (
             <h1 title='一个标题'>{this.state.state1}</h1>
        )
   }
}

ReactDOM.render(<H2 titleData="the data of user"/>, document.getElementById('app'));

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

class H2 extends React.Component {
   state = {
       state1: '1223'
   }
   render() {
        return (
             <h1 title='一个标题'>{this.state.state1}</h1>
        )
   }
}

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

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

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

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

<FormattedDate date={this.state.date} />

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

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

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

八、事件处理

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

function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }
<button onClick={activateLasers}>
  Activate Lasers
</button>

当使用 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 (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  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 (
      <button onClick={this.handleClick.bind(this)}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  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 (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

九、列表生成

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

函数组件形式

    function NumList(props) {
        const nums = props.nums;
        const list = nums.map((item) => {
            return <li>{item}</li>
        })

        return(
            <ul>
                {list}
            </ul>
        )
    }
    const nums = [1,2,3];
    ReactDOM.render(<NumList nums={nums} />,document.getElementById('app'));

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

 function NumList(props) {
        const nums = props.nums;
        const list = nums.map((item) => {
            return <li key={item.toString()}>
                    {item}
                   </li>
        })

        return(
            <ul>
                {list}
            </ul>
        )
    }
    const nums = [1,2,3];
    ReactDOM.render(<NumList nums={nums} />,document.getElementById('app'));

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

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

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

    function NumList(props) {
        const nums = props.nums;
        return(
            <ul>
                {nums.map((item) => {
                    return <li key="{item.toString()}">{item}</li>
                })}
            </ul>
        )
    }
    const nums = [1,2,3];
    ReactDOM.render(<NumList nums={nums} />,document.getElementById('app'));
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容