一、React 基础知识
1. React.createElement
React.createElement 是 jsx 语法的编译结果,这个函数用来创建一个 React 元素,它的返回值是一个 Virtual DOM(虚拟DOM)。
React.createElement(type, props, ...children)
第一个参数为元素类型,可以是标签名或组件名,第二个参数为元素属性,第三个参数为子节点列表。
const html1 = <h1>hello</h1>;
const html2 = React.createElement('h1', null, 'hello');
以上2种写法是等价的,可以看到使用 jsx 语法更加简介直观。
2. ReactDOM.render
ReactDOM.render(cpn, dom) 方法用来将一个 react 组件渲染到 DOM 元素上。
第一个参数为要渲染的组件,可以是 jsx 语句;第二个参数为要渲染到的真实 DOM 元素。
ReactDOM.render(<h1>hello</h1>, document.getElementById('reactApp'));
二、定义组件
1. 类组件
使用关键字 class 定义的组件。需要继承 React.Component 类,重写 render 方法,在 render 方法中返回 jsx 语法定义的组件。
// 类组件
export default class Person extends React.Component {
render() {
return <div>hello world</div>;
}
}
2. 函数组件
使用关键字 function 定义的组件。返回 jsx 语法定义的组件。
export default function Person() {
return <div>hello web</div>;
}
3. 注意事项
(1) 组件名的首字母必须大写,首字母大小写是 react 区分组件和普通标签的方法。
(2) 组件中返回的 jsx 代码必须有且只有1个顶层标签。
4. 组件嵌套
父组件嵌套子组件,将子组件的组件名当作标签名按标签的方式使用即可。
// 子组件
function Son() {
return <div><p>这是子组件</p></div>;
}
// 父组件
export default function Father() {
// return <div><h3>这是父组件</h3><Son></Son></div>;
return <div><h3>这是父组件</h3><Son /></div>; // 和上面一句写法等价
}
注意: 组件当作标签使用的时候,必须是闭合标签。
三、JSX 语法
JSX 是 JS 的扩展语言,本质还是 JS。
1. 表达式
jsx 使用 { expression } 的方式获取表达式的值。
在 jsx 中如果需要使用 js 表达式,需要写在花括号({})内。
const name = 'zhangsan';
export default function Person() {
return <div><h3>{ name }</h3></div>;
}
在页面渲染时,name 会被渲染成 zhangsan。
jsx 本身也是一个表达式,可以定义一个 jsx 表达式变量,可以在创建组件时直接返回此变量。
const name = 'lisi';
const html = <div><h3>{ name }</h3></div>;
export default function Person() {
return html;
}
2. 属性
此外,还可以在 jsx 中加入属性。
export default function Person() {
return <div id="div"><h3></h3></div>;
}
如果我们直接用 html 的方式定义属性,那渲染到页面后,Person 组件中 div 的 id 就是 div。
如果想要用表达式作为属性值,同样也是使用花括号。
const div = 'div1';
export default function Person() {
return <div id={div}><h3></h3></div>;
}
这时 div 的 id 就为 div1。
无论在 jsx 内容还是属性或者是 jsx 本身,都可以使用 js 表达式。
3. className
jsx 中不能使用 class 给元素添加类名。jsx 中 jsx 本身也是 js,在 js 中 class 是 js 的关键字,因此需要使用 className 给元素添加类名。
const div = 'div1';
const className = 'div2';
export default function Person() {
return <div id={div} className={ className }><h3></h3></div>;
}
这时 div 就有了一个 class 为 div2。
4. jsx 自动展开数组
在 jsx 中,数组会自动进行展开。
const arr = ['zhangsan', 'lisi', 'wangwu'];
export default function Person() {
return <div>{ arr }</div>;
}
此时页面上将渲染出 zhangsanlisiwangwu:
也可以使用数组来渲染一组标签:
const arr = [<p key='1'>c++</p>, <p key='2'>python</p>, <p key='3'>php</p>];
export default function Person() {
return <div>{ arr }</div>;
}
在页面上将渲染为一组 p 标签:
5. 三元运算
在 jsx 中可以使用三元表达式来控制某个元素是否渲染。
const bl = true;
export default function Person() {
return <div>{ bl ? <h3>hello world</h3> : null }</div>;
}
当 bl 为 true 时,页面上会渲染出 h3 标签;当 bl 为 false 时,就不渲染。
这个功能还有一种更简单的方式:
const bl = true; export default function Person() { return <div>{ bl && <h3>hello world</h3> }</div>; }
使用且运算,当 bl 会真时,继续向后运算;bl 为假时,就终止。
6. 循环
要在 jsx 中使用循环,需要使用 map。
const arr = [{ id: 1, name: 'zhangsan', age: 10 }, { id: 2, name: 'lisi', age: 15 }, { id: 3, name: 'wangwu', age: 20 }];
export default function Person() {
return <div>
<ul>
{ arr.map(item => <li key={ item.id }>{ item.name },{ item.age }</li>) }
</ul>
</div>;
}
7. 事件
on + 事件名 给组件标签添加事件。
- 事件名的首字母必须大写。
- 类组件中的 jsx 中的 this 指向实例对象。
export default function Person() {
function fn() {
console.log('hello world');
}
return <div>
<button onClick={fn}>按钮</button>
</div>;
}
点击按钮时,控制台就会打印出 hello world。
可以给函数 fn 传递参数,遵循以下规则。
函数传参:
(1) 默认传递一个参数事件对象
按钮的点击事件会默认传入一个事件对象,我们可以使用一个参数来接收。
export default function Person() {
function fn(e) {
console.log(e); // SyntheticBaseEvent 事件对象
}
return <div>
<button onClick={fn}>按钮</button>
</div>;
}
(2) 通过箭头函数自定义传参
export default function Person() {
function fn(e, a) {
console.log(e); // SyntheticBaseEvent 事件对象
console.log(a); // hello
}
return <div>
<button onClick={(event) => fn(event, 'hello')}>按钮</button>
</div>;
}
这里我们使用一个箭头函数作为按钮的点击事件,接收事件对象并和其他参数一起传递给 fn。
(3) 通过 bind 方法
export default function Person() {
function fn(e, a) {
console.log(e); // world
console.log(a); // SyntheticBaseEvent 事件参数
}
return <div>
<button onClick={fn.bind(null, 'world')}>按钮</button>
</div>;
}
使用 bind 方法也可以实现自定义传参,此时第一个参数为 bind 方法传入的 world,第二个参数是事件对象。