React Element /组件/JSX

  React是一个JavaScript的UI库,通过Javascript来构建UI(用户界面(创建Html元素)),但使用者确不需要操作DOM,只需要描述DOM,React会帮你创建DOM,所以写React就是描述DOM长什么样子。在JS中,描述一个东西通常使用对象,有哪些属性,值是什么。React提供了方法来创建对象,React 17以前是createElement(),以后是Jsx(),它们都接受三个参数,type(创建什么类型元素),  properties(元素有哪些属性),children(元素有哪些子元素)。创建一个h1元素,它有id属性,children是Hello World,

let h1Elem = React.createElement('h1', {id: 'recipe'}, 'Hello World');

  使用React方法创建的对象称React Element。react-dom库的render方法创建真实的DOM,第一个参数是React element, 第二个参数是渲染到什么地方,

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

  ReactDom render相当于执行以下操作

let h1 = document.createElement('h1');
h1.setAttribute('id', 'recipe');
h1.textContent = 'Hello World';
document.getElementById('root').appendChild(h1);

  浏览器就可以渲染出h1,构建出UI。写React就是创建React Element,创建真实的DOM,React会负责,所以React开发需要引入两个库: react 和react-dom。最开始了解React,完全可以使用script标签引入的方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React</title>
    <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script>
        let h1Elem = React.createElement('h1', { id: 'recipe' }, 'Hello World');
        ReactDOM.render(h1Elem, document.getElementById('root'));
    </script>
</body>
</html>

  其实,createElement可以接受任意个参数,第三个参数及其以后的参数,都会当成创建出来的React Element的children,

let ulElem = React.createElement('ul', null,
    React.createElement('li', null, 'JS'),
    React.createElement('li', null, 'React'),
    React.createElement('li', null, 'Redux')
);
ReactDOM.render(ulElem, document.getElementById('root'));

  ul下面三个li,简单的树形结构,整个Web应用(html文档)也是一个树形结构,都可以通过这种方式创建。当页面其他地方也用ul li,可以封装起来,最简单的就是写个函数 

const Content = () => {
  return React.createElement('ul', null,
    React.createElement('li', null, 'JS'),
    React.createElement('li', null, 'React'),
    React.createElement('li', null, 'Redux')
  )
}

  这就形成了React组件。组件包含一段React element ,相当于自定义了一个type。自定义类型要求组件名大写,以进行区分,还要求返回一个单一的根节点,一个类型一个根节点,这和树形结构有关,一棵子树,插入到整棵树上,一个根节点,最好操作。把组件名传给createElement 函数中的第一个参数type, 

// 组件名Content, 相当于createElement函数中的第一个参数type, 
let content = React.createElement(Content, null, null);
ReactDOM.render(content, document.getElementById('root'));

  创建React组件的方式还有点问题,一是数据和UI绑定,组件不够通用,二是语法繁琐。数据和UI分离相对好解决,createElement第二个参数是属性, 组件也能定义属性

const item = ['JS', 'React', 'Redux'];
// 向组件中传递一个数组数据 item 
let content = React.createElement(Content, {item: item}, null);

  组件获取属性,则是通过props参数。React DOM 渲染时,会给组件注入一个参数,包含组件定义的所有属性,所以组件的参数名通常定义为props。

// 自动获取props作为参数。
const Content = (props) => {
  return  React.createElement('ul', null, 
    props.item.map((item, index) => 
      React.createElement('li', {key:index}, item)
    )
  )
}

  React函数组件和普通的函数有两个区别,一个是函数名大写,一个是只有一个参数props,如果不写props,只能使用解构赋值,也就是说,组件的参数要么是props,要么以大括号开始。

  语法繁琐的问题,React element是描述html元素,html标签也是描述html元素,能不能在JS中直接写html标签?这就是JSX,直接在JS代码中写html标签。ReactElement中的type,属性和children,对应html中的标签、属性和children,<h1 id='recipe' >Hello World</h1>, <Content items={items} >Content</Content>。JSX只是对JS进行扩展,它始终都是JS语法(写在.js文件中),JS中的所有语法,它都支持,JS中所有要求,它也必须遵守。扩展还包括属性是任意的类型,不仅仅是字符串,不过要用大括号包起来。在JSX中, {}里面的内容都当作JS表达式,需要求值。num = {1},bool={false}。<Content item ={item} name="sam" bool={false} num={1}></Content>。传递属性还可以用{...obj}。const obj = {name:”sam”, num: 1} , …obj就相当于name=”sam” , num= 1

const Content = ({ items, name, bool, num }) => {
    console.log(items, 'items')
    return <ul>
        {
            items.map((item, index) => {
                return (<React.Fragment> {bool && <li key={index}>{name} - {item} - {num}</li>}</React.Fragment>)
            })
        }
    </ul>
}

const items = ['JS', 'React', 'Redux'];
let content = <Content items={items} name="sam" bool={true} num={1} />;
// 或者
const obj = { items: ['JS', 'React', 'Redux'], name: 'sam', bool: true, num: 1}
let content = <Content {...obj} />;

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

  要求就是html语法不能使用JS的保留字和关键字。html元素经常添加class属性,但class在js中是关键字,class要变成className. 还有for,要用htmlFor,<label htmlFor=”input” className=”text”></label>。还有style属性,必须是一个对象,一些属性带浏览器厂商前缀,是用-,但-在JS中表示减法,这时前缀首字母必须大写, 所有的样式都是字符串

const inlineStyle = {
    color: 'pink',
    WebkitFilter: 'blur(5px)' //  -wibkit-filter
}
return <ul style={inlineStyle}> ...</ul>

  JSX是JS的扩展,但浏览器并没有支持该扩展,需要把它转换成JS。引入babel库,在head 标签中引入

<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

  然后<script type="text/babel">告诉babel, 哪些代码需要转译。有了JSX,重写代码如下

<script type="text/babel">
    const Content = ({ items, name, bool, num }) => {
        return <ul>
            {
                items.map((item, index) => {
                    return (<React.Fragment> {bool && <li key={index} >{name} - {item} - {num}</li>}</React.Fragment>)
                })
            }
        </ul>
    }
    const App = () => {
        const items = ['JS', 'React', 'Redux', 'Java'];
        return <div>
            <header>Header</header>
            <Content items={items} name="sam" bool={true} num={1} />;
        </div>
    }

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

  但在大型应用程序中,这么写React肯定有问题,开发不友好,运行时编译慢,于是就要使用构建工具。好在官方推出脚手架工具create-react-app,直接创建项目,进行开发。它和我们上面的开发的最大不同就是,一个组件一个JS文件,通过export和import进行组合,其他没什么区别。App.js是整个项目的入口,只有能被App.js引入,不管是直接引入,还是间接引入,都能渲染到页面上。在src目录下新建Content.js

export function Content({ items, name, bool, num }) { // export出Content组件
    return <ul>
        {
            items.map((item, index) => {
                return (<React.Fragment> {bool && <li key={index} >{name} - {item} - {num}</li>}</React.Fragment>)
            })
        }
    </ul>
}

  App.js

import { Content } from './Content'; //引入Content组件

function App() {
  const items = ['JS', 'React', 'Redux', 'Java'];
  return (
    <div>
      <header>Header</header>
      <Content items={items} name="sam" bool={true} num={1} />;
    </div>
  );
}
export default App;

  

posted @ 2017-04-20 19:32  SamWeb  阅读(26299)  评论(0编辑  收藏  举报