创建项目
1.安装脚手架Create React App。
npm install -g create-react-app
2.创建项目
create-react-app reactapp(项目名称可以自定义)
React Jsx
1、JSX执行更快,编译为JavaScript代码时进行优化
2、类型更安全,编译过程如果出错就不能编译,及时发现错误
注意:
1、JSX必须要有根节点。
2、正常的普通HTML元素要小写。如果是大写,默认认为是组件。
JSX表达式
1、中间如果需要插入变量用{}
2、{}中间可以使用表达式
3、{}中间表达式中可以使用JSX对象
4、属性和html内容一样都是用{}来插入内容
5.绑定属性注意:
class 要变成 className
for 要变成 htmlFor
style属性和以前的写法有些不一样:
React组件
函数式组件与类组件的区别和使用,函数式比较简单,一般用于静态没有交互事件内容的组件页面。类组件,一般又称为动态组件,那么一般会有交互或者数据修改的操作。
1、函数式组件
function Childcom(props){
console.log(props)
let title = <h2>我是副标题</h2>
let weather = props.weather
//条件判断
let isGo = weather=='下雨' ?"不出门":"出门"
return (<div>
<h1>函数式组件helloworld</h1>
{title}
<div>
是否出门?
<span>{isGo}</span>
</div>
</div>
)
}
2.类组件
class HelloWorld extends React.Component{
constructor(props) {
super(props);
}
render(){
return (<div>
<h1>类组件定义HELLOWORLD</h1>
<h1>hello:{this.props.name}</h1>
<Childcom weather={this.props.weather} />
</div>
)
}
}
注意:
1、组件的构造函数中一定要注意 super,子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象
constructor(props){
super(props); /*用于父子组件传值 固定写法*/
this.state={
userinfo:'张三'
}
}
2、组件名称首字母大写、组件类名称首字母大写
3、为什么官方的列子里面写个super(props):只有一个理由需要传递props作为super()的参数,那就是你需要在构造函数内使用this.props
那官方提供学习的例子中都是写成super(props),所以说写成super(props)是完全没问题的,也建议就直接这样写。
4.React是单项数据流,父组件改变了属性,那么子组件视图会更新。
5.属性 props
是外界传递过来的,状态 state
是组件本身的,状态可以在组件中任意修改
6.构造函数的作用:
用来新建父类的this对象;子类必须在constructor方法中调用super方法;否则新建实例时会报错;因为子类没有自己的this对象;
而是继承父类的this对象,然后对其进行加工。如果不调用super方法;子类就得不到this对象。
state和props的区别
假如我们有个父组件,可以在父组件的state里定义子组件的数据比如:
this.setState({ childData: 'Child Data' });
紧接着,在父组件的render()
方法里面,可以将父组件的state
,作为子组件的props
传递下去,如下
<Child data = {this.state.childData}/>
这样就可以父组件的state
传递给子组件的props
。从子组件的角度来看,props
是不可变的。如何改变子组件的props?我们仅仅需要改变父组件内部的state
即可,父组件的state
改变之后,引起父组件重新渲染,在渲染的过程中,子组件的data
变成父组件this.state.childDtat
的值。这样父组件内部state
改变,就会引起子组件的改变。
这样就形成里从上而下的数据流,也就是React常说的单向数据流,这个“向”是向下。
我们常常利用这个原理更新子组件,从而衍生出一种模式,父组件:处理复杂的业务逻辑、交互以及数据等。子组件:称它为Stateless
组件即无状态组件,只用作展示。在我们开发过程中,尽可能多个使用无状态组件,可以缕清业务之间的逻辑关系,提高渲染效率。
如果子组件想要改变自身的data
,这时候需要,父组件传递给子组件一个方法,改变父组件自身的state
。
父组件:
<Child data={this.state.childData} handleChange={this.handelChildChange}></Child>
子组件接收父组件方法
let Chilid = ({data,handleChange}) =>
绑定事件处理函数this的3种方法
第一种方法:
run(){
alert(this.state.name)
}
<button onClick={this.run.bind(this)}>按钮</button>
第二种方法:
//构造函数中改变
constructor(props) {
super(props);
this.run = this.run.bind(this);
}
run(){
alert(this.state.name)
}
<button onClick={this.run>按钮</button>
第三种方法:
//箭头函数
run=()=> {
alert(this.state.name)
}
<button onClick={this.run}>按钮</button>
react中父子组件传值
父子组件:组件的相互调用中,我们把调用者称为父组件,被调用者称为子组件
父子组件传值:
父组件给子组件传值
1.在调用子组件的时候定义一个属性
2.子组件里面 this.props.msg
说明:父组件不仅可以给子组件传值,还可以给子组件传方法,以及把整个父组件传给子组件。
父组件主动获取子组件的数据
1、调用子组件的时候指定ref的值
2、通过this.refs.header 获取整个子组件实例
注意:props可以传递函数,props可以传递父元素的函数,就可以去修改父元素的state,从而达到传递数据给父元素。
父传子数据传递案例:
//父组件
class Father extends React.Component {
constructor(props) {
super(props);
this.state = {
msg:"首页信息",
title:"首页头部"
};
}
run=()=>{
alert("我是父组件的run方法");
}
getData=()=>{
alert(this.state.title);
}
//获取子组件传过来的值
getChilddata=(result)=>{
alert(result);
}
//父组件主动调用子组件的数据和方法
getHeader=()=>{
alert(this.refs.Header.state.msg);//获取子组件的数据
this.refs.Header.run(); //获取子组件的方法
}
render() {
return (<div>
<Header ref='Header' title={this.state.title} run={this.run} Father={this}></Header>
<hr></hr>
{this.state.msg}
<hr></hr>
<button onClick={this.getHeader}>父组件主动调用子组件的数据和方法</button>
</div>
);
}
}
//子组件
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
data:'lzx',
msg:"子组件信息"
};
}
run=()=>{
alert('子组件方法');
}
getFather=()=>{
alert(this.props.Father.state.title);
}
render() {
return (
<div>{this.props.title}
<br/>
<button onClick={this.props.run}>调用父组件run方法</button>
<br></br>
<button onClick={this.props.Father.getData}>调用父组件的getData方法</button>
<br></br>
<button onClick={this.getFather}>获取整个father实例</button>
<br></br>
<button onClick={this.props.Father.getChilddata.bind(this,this.state.data)}>父组件中获取子组件传过来的值</button>
</div>
);
}
}
react生命周期函数
组件加载之前,组件加载完成,以及组件更新数据,组件销毁。 触发的一系列的方法 ,这就是组件的生命周期函数
组件加载的时候触发的函数:
constructor 、componentWillMount、 render 、componentDidMount
组件数据更新的时候触发的生命周期函数:
shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
你在父组件里面改变props传值的时候触发的:
componentWillReceiveProps
组件销毁的时候触发的:
componentWillUnmount
必须记住的生命周期函数:
加载的时候:componentWillMount、 render 、componentDidMount(dom操作)
更新的时候:componentWillUpdate、render、componentDidUpdate
销毁的时候: componentWillUnmount
class Lifecycle extends React.Component {
constructor(props) {
console.log('1.构造函数');
super(props);
this.state = {
msg:'我是一个msg'
};
}
//组件将要挂载触发的生命周期函数
componentWillMount(){
console.log('2.组件将要挂载');
}
//组件挂载完成触发的生命周期函数
componentDidMount(){
//dom操作放在这里面 请求数据也放在这里面
console.log('4.组件挂载完成');
}
//是否要更新数据
shouldComponentUpdate(nextProps,nextState){
console.log('01.是否要更新数据');
console.log(nextProps);
console.log(nextState);
return true;
}
//组件将要更新时触发
componentWillUpdate(){
console.log('02.组件数据将要更新');
}
//组件更新完成
componentDidUpdate(){
console.log('03.组件数据更新完成');
}
setMsg=()=>{
this.setState({
msg:"我是改变后的msg"
})
}
//组件销毁时触发的生命周期函数 用在组件销毁时执行操作
componentWillUnmount(){
console.log('组件销毁了');
}
//
componentWillReceiveProps(){
console.log('父子组件传值,父组件里面改变了props的值触发的方法');
}
render() {
console.log('3.数据渲染');
return (
<div>
生命周期函数演示----{this.state.msg}----{this.props.title}
<br></br>
<button onClick={this.setMsg}>改变msg</button>
</div>
);
}
}
React 路由
安装:npm install react-router-dom --save
ReactRouter三大组件:
Router:所有路由组件的根组件(底层组件),包裹路由规则的最外层容器。
属性:basename->设置跟此路由根路径,router可以在1个组件中写多个。
Route:路由规则匹配组件,显示当前规则对应的组件
Link:路由跳转的组件
注意:如果要精确匹配,那么可以在route上设置exact属性。
//Router使用案例
import React from 'react';
//hash模式
//import {HashRouter as Router,Link,Route} from 'react-router-dom'
//history模式/后端匹配使用
import {BrowserRouter as Router,Link,Route} from 'react-router-dom'
function Home(){
return (
<div>
<h1>admini首页</h1>
</div>
)
}
function Me(){
return (
<div>
<h1>admin个人中心</h1>
</div>
)
}
function Product(){
return (
<div>
<h1>admin产品页面</h1>
</div>
)
}
class App extends React.Component{
render(){
return (
<div id="app">
{/* <div>所有页面普通内容</div> */}
<Router>
<Route path="/" exact component={()=>(<div>首页</div>)}></Route>
<Route path="/me" component={()=>(<div>me</div>)}></Route>
<Route path="/product" component={()=>(<div>product</div>)}></Route>
</Router>
<Router>
<div className="nav">
<Link to="/">Home</Link>
<Link to="/product">Product</Link>
<Link to="/me">个人中心</Link>
</div>
<Route path="/" exact component={Home}></Route>
<Route path="/product" component={Product}></Route>
<Route path="/me" exact component={Me}></Route>
</Router>
</div>
)
}
}
React中使用Antd
1、安装antd npm install antd --save / yarn add antd / cnpm install antd --save
2、在您的react项目的css文件中引入 Antd的css
@import ‘~antd/dist/antd.css’;
3、看文档使用:
如使用Button:
1、在对应的组件中引入Antd import { Button } from ‘antd’;
2、<Button type="primary">Primary</Button>
Antd按需引入
我们现在已经把组件成功运行起来了,但是在实际开发过程中还有很多问题,例如上面的例子实际上加载了全部的 antd 组件的样式(对前端性能是个隐患)。
1、安装antd npm install antd --save
2、安装(react-app-rewired)一个对 create-react-app 进行自定义配置的社区解决方案
yarn add react-app-rewired / cnpm install react-app-rewired --save
3、修改 package.json
react-scripts 需改为react-app-rewired
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom",
"eject": "react-app-rewired eject"
}
4、在项目根目录创建一个 config-overrides.js 用于修改默认配置
module.exports = function override(config, env) {
// do stuff with the webpack config...
return config;
};
5、安装babel-plugin-import babel-plugin-import是一个用于按需加载组件代码和样式的 babel 插件
yarn add babel-plugin-import / cnpm install babel-plugin-import --save
6、修改 config-overrides.js
const { injectBabelPlugin } = require(‘react-app-rewired’);
module.exports = function override(config, env) {
config = injectBabelPlugin(
['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }],
config,
);
return config;
};
7、然后移除前面在 src/App.css 里全量添加的 @import ‘~antd/dist/antd.css’; 直接引入组件使用就会有对应的css
import { Button } from ‘antd’;
<Button type="primary">Primary</Button>