1.第一种创建组件的方式
使用构造函数来创建组件,如果要接收外界传递的数据,需要在构造函数的参数列表中使用props来接收;
必须要向外return一个合法的JSX创建的虚拟DOM
●创建组件:
注意:组件首字母必须要大写,否则就会被当作一个普通标签来渲染,浏览器就识别不了报错
function Hello(){ //如果在一个组件中return一个null,则表示此组件是空的,什么都不会渲染 //return null; //在组件中必须返回一个jsx虚拟DOM元素 return <div>这是function创建的Hello组件</div> }
●为组件传递数据:
const dog = { name:'大黄', age: 3, gender: '雄' }
// ...为展开运算符,将dog里的属性全部展开,即...dog就相当于name={dog.name} age={dog.age} gender={dog.gender}
ReactDOM.render(<div> {/*直接把组件的名称以标签的形式丢到页面上即可 */} {/* <Hello name={dog.name} age={dog.age} gender={dog.gender}></Hello> */} <Hello {...dog}></Hello> </div>,document.getElementById('app')); //在构造函数中接受外界传递过来的数据 function Hello(props){ //结论:不论是vue还是React,组件中的props永远都是只读的,不能被重新赋值 //props.name = 'zs'; //报错 return <div>这是function创建的Hello组件 -- {props.name} --{props.age} --{props.gender}</div> }
以上代码都是写在同一个js文件里,实际上我们开发为了保持代码的简洁性,会将组件封装到单独的文件中:
●创建一个Hello.jsx的文件:
import React from 'react' //创建并导出组件 export default function Hello(props){ //如果在一个组件中return一个null,则表示此组件是空的,什么都不会渲染 //return null; //在组件中必须返回一个jsx虚拟DOM元素 console.log(props); //结论:不论是vue还是React,组件中的props永远都是只读的,不能被重新赋值 //props.name = 'zs'; //报错 return <div>这是function创建的Hello组件 -- {props.name} --{props.age} --{props.gender}</div> }
●在其他文件里导入组件:
//导入Hello组件 //默认如果不做单独的配置的话,不能省略.jsx后缀名 import Hello from './components/Hello.jsx'
如果想要省略后缀名,需要在webpack.config.js文件中添加配置:
resolve: { extensions: ['.js','.jsx', '.json'] //表示这几个文件的后缀名,可以省略不写,顺序从左到右 }
导入组件时,配置和使用@路径符号:
resolve: { extensions: ['.js','.jsx', '.json'], //表示这几个文件的后缀名,可以省略不写,顺序从左到右 alias: { //表示别名 '@': path.join(__dirname,'./src') } }
//注意:这里的@符号表示项目根目录中的src这一层目录 import Hello from '@/components/Hello'
2.第二种创建组件的方式: 基于class关键字创建组件
●组件的基本结构:
//如果要使用class定义组件,必须要让自己的组件继承React.Component class 组件名称 extends React.Component{ //在组件内部,必须有render函数 render(){ //render函数中必须返回合法的JSX虚拟DOM结构 return <div>这是class创建的组件</div> } }
●创建组件:
//class关键字创建组件 class Movie extends React.Component{ //由于Movie组件继承了React.Component,所以自定义的构造其中必须调用super() constructor(){ super(); } //render函数的作用是渲染当前组件所对应的虚拟DOM元素 //render是实例方法 render(){ return <div> 这是Movie组件 </div> } }
●为组件传递数据:
const user = { name: '张三', age: 22, gender: '男' } //class关键字创建组件 class Movie extends React.Component{ //由于Movie组件继承了React.Component,所以自定义的构造其中必须调用super() constructor(){ super(); } //render函数的作用是渲染当前组件所对应的虚拟DOM元素 //render是实例方法 render(){ //注意:不管是用function创建组件还是使用class创建组件,props属性都是只读的 //this.props.name = '李四'; //报错 //在class关键字创建组件中,如果想使用外界传递过来的props参数,不需要接收,直接通过this.props.***访问 return <div> {/*在class组件内部,this表示当前组件的实例对象 */} 这是Movie组件 -- {this.props.name} -- {this.props.age} -- {this.props.gender} </div> } } ReactDOM.render(<div> {/*这里的Movie标签其实就是Movie类的一个实例对象 */} <Movie {...user}></Movie> </div>,document.getElementById('app'));
●class关键字创建的组件的私有属性state:
//class关键字创建组件 class Movie extends React.Component{ //由于Movie组件继承了React.Component,所以自定义的构造其中必须调用super() constructor(){ super(); //只有调用了super()以后才能使用this关键字 // this.state = {}相当于Vue中的data() {return {}} this.state = { msg: '大家好,我是class创建的Movie组件' }; } //render函数的作用是渲染当前组件所对应的虚拟DOM元素 render(){ //state里面的数据是可读可写的 this.state.msg = 'msg的值被我修改了'; return <div> {/*在class组件内部,this表示当前组件的实例对象 */} 这是Movie组件 <h3>{this.state.msg}</h3> </div> } } ReactDOM.render(<div> {/*这里的Movie标签其实就是Movie类的一个实例对象 */} <Movie></Movie> </div>,document.getElementById('app'));
3.两种创建组件方式的对比
注意:使用class关键字创建的组件有自己的私有数据和生命周期函数;
但是使用function创建的组件只有props,没有自己的私有数据和生命周期
(1)用构造函数创建出来的组件叫做“无状态组件”
(2)用class关键字创建出来的组件叫做“有状态组件”
(3)什么情况下使用有状态组件?什么情况下使用无状态组件?
●如果一个组件需要有自己的私有数据,则推荐使用有状态组件
●如果一个组件不需要有自己的私有数据,则推荐使用无状态组件
●无状态组件由于没有自己的state属性和生命周期函数,所以运行效率会比有状态组件稍微高一些
有状态组件和无状态组件之间的本质区别就是:有无state属性和有无生命周期函数
(4)组件中的props和state/data之间的区别:
●props中的数据都是外界传递过来的
●state/data中的数据都是组件私有的(通过Ajax获取回来的数据一般都是私有数据)
●props中的数据都是只读的,不能重新赋值;state/data中的数据都是可读可写的