搭建React项目
在装有node.js的基础上,命令行输入命令
npx create-react-app item-name
即可创建一个React项目,项目结构如下
JSX语法
src文件下的index.js是项目的入口文件,文件中先后引入了react和react-dom两个库。
ReactDOM.render(<h2>hello react</h2>, document.getElementById('root'));
ReactDOM实例通过render方法,将前面的h2标签元素,添加到root元素中,而id为root的元素是public文件的index.html文件的元素。
JSX语法由JavaScript语法 和 XML语法组成,通俗来说就是,当我们在JSX语句中遇到 <> 的形式的,按照XML的形式来解析,因为他们是标签;遇到 {} 按照javaScript来解析,表示JS语法。
const a = (
<div>
<p>hello react</p>
</div>
)
如果存在标签结构,并且标签结构需要换行的话,可以使用 ()的形式进行表示
React 元素渲染
这里通过一个实例了解react的元素渲染
<!-- 首先定义一个方法 -->
function nowTime() {
const ele = (
<!-- 使用()的形式,可以换行写标签语法 -->
<h2>get now time</h2>
<!-- 定义一个获取当前时间的方法 -->
<h1>now time is { new Date().toLocalTimeString() } </h1>
)
<!-- 渲染这个获取当前时间的方法 -->
reactDOM.render(ele, document.getElementById('root));
}
<!-- 定时器每隔一秒会调用一次该方法,实现实时更新当前时间 -->
setInterval(() => {
nowTime()
},1000)
React 组件
关于Ract组件,区别于vue的以 .vue为后缀结尾的文件,React的组件可以是以 .js 为后缀的文件,也可以是 .jsx 为后缀的文件命名。编写React组件的时候,创建 .js 的组件是没有代码语法提示的,而创建 .jsx 组件文件是有代码语法提示的。 创建React组件分别有两种方式,第一种是通过 类的形式创建组件,第二种是通过Hook的形式创建。并且组件之间是可以互相引入和使用的,以标签的形式存在!
<!-- 第一种写法 -->
<!-- 创建一个React组件首先需要引入 React 库 -->
import React from 'react'
<!-- 创建一个类App继承React所提供的Component组件的对象 -->
class App extends React Component {
<!-- rander(){} 渲染函数 -->
render() {
<p>渲染函数中写你需要这个组件展示的内容,或者要做什么</p>
}
}
<!-- 导出组件 -->
export default App
<!-- 第二种写法 -->
import React from 'react'
export default class App extends React.Component{
render() {
return {
<div>
<p>直接导出并继承React下的Component对象</p>
</div>
}
}
}
<!-- 函数组件 -->
function fun(props) {
return (
<div>
<h3>函数组件</h3>
</div>
)
}
<!-- ES6 class类组件 -->
class App extends React.Component {
render() {
return (
<div>
<h3>ES6 class类创建组件</h3>
</div>
)
}
}
然后在需要使用的地方引入该组件,并将其放置在渲染函数中渲染即可。
import 'App' from './App.jsx'
ReactDOM.render(<App />, document.getElementById('root));
Props组件动态传参
React里面的组件传参通过 props
父组件传递参数给子组件
<!-- 子组件 -->
import React from 'react'
export default class Son extends React.Component {
render() {
return {
<div>
<ul>
{
<!-- 子组件中 通过this.props的方式获取父组件传递过来的数据,也就是arr ,然后通过map来遍历获取到的数据-->
this.props.arr.map((element, index) => {
<!-- 将遍历得到的数据放在li标签中渲染返回,key值需要绑定index唯一值,否则会抛出语法error -->
return <li key={ index }>{ element }</li>
})
}
</ul>
</div>
}
}
}
import React from 'react'
<!-- 引入子组件 -->
import Son from './son'
export default class Father extends React.Component {
render() {
<!-- 父组件定义两个数组,用于传递给子组件使用 -->
const arrOne = ['Vue' , 'React', 'Angular'],
arrTwo = ['Java', 'Pythen', 'C++']
return (
<!-- 在两个子组件中分别传入不同的数据 -->
<Son arr={ arrOne } />
<Son arr={ arrTwo } />
)
}
}
子组件传递参数给父组件
<!-- 父组件 -->
import React from 'react'
import Son from './son'
export defaul{t class Father React.Component {
<!-- 首先定义state用来存储title的状态 -->
constructor() {
super();
this.state = {
title: ‘最初的标题’
}
}
clickChange = () => {
this.setState({
title: '最后的标题'
})
}
render() {
return (
<div>
父子组件传参
</div>
<!-- 使用子组件,title最开始为 ‘最初的标题’, changeFatherProps 被子组件中的点击事件触发从而执行父组件中的clickChange方法,完成对标题的修改 -->
<son title={ this.state.title } changeFatherProps={ this.clickChange } />
)
}
}
<!-- 子组件 -->
import React from 'react'
export defaul{t class Father React.Component {
changeFather = () => {
<!-- 通过 this.props 的方式 -->
this.prpos.changFatherProps()
}
render() {
return <div>
父子组件传参
<!-- 点击button事件会触发父组件中方法的执行,将标题修改 -->
<button onClick={ this.changeFather }>点击传参修改<button>
</div>
}
}
state 状态
<!-- 通过this.state定义保存数据和状态 -->
this.state = {
flag: true,
count: 10,
}
<!-- 需要修改状态值的时候通过 this.setState({})的方式进行修改 -->
this.setState({
flag: false,
count: this.state.count ++
})
生命周期函数
随着我们对React理解和使用的原来越多,生命周期会越来越有参考价值
生命周期函数包括:
- componentWillMount: 在组件创建之前执行
- componentDidMount: 在组件渲染之后执行
- shouldComponentUpdata: 返回 true 和 false, true代表允许改变, false代表不允许改变
- componentWillUpdata: 数据在改变之前执行(state, props)
- conponentDidUpdata: 代表数据修改完成(state, props)
- conponentWillReveiceProps: props发生改变时执行的生命周期函数
- conponentWillUnMount: 组件卸载前执行
探讨关于 setState 更新是同步操作还是异步操作的问题
setState会引起视图的重绘
官方文档解答:在可控的情况下是异步的,在不可控的情况下是同步的
create-react-app 按需加载Antd 组件
- 命令行输入 cnpm run eject 拉取React的配置文件
- 文件被修改时,会抛出异常,由于GIt的原因导致,此时找到文件目录,按下shift + command + . 显示隐藏文件,删除 .git 文件,重新 cnpm run eject即可,安装完成后目录多出了两个文件,分别是config和script文件,config文件就是webpack配置文件
- 安装一个依赖文件 cnpm install babel-plugin-import --save-dev
React-Router
React路由也分为两种路由模式: BrowserRouter 和 HashRouter
两者的区别在于 HashRouter使用的是锚点链接的形式,表现为 # 的形式, # 号后面为跳转的二级路由地址 而BrowserRouter 则使用了HTML5的新特性,主要是 history.push() 实现。
实际开发中, BrowserRouter 会在项目上线之后存在一些问题,就是需要后台配合做一些配置处理和重定向,否则会很容易跳转到 404 页面,而 HashRouter 则不会有这个问题。
<!-- 安装 react-router -->
cnpm install react-router-dom -save
<!-- 使用 react-router -->
import {BrowserRouter as Router, Link,NavLink, Route, Redirect} from "react-router-dom"
<!-- 引入 react-router 相关的组件 -->
function App() {
render() {
return(
<div>
<!-- 在 Router盒子中嵌套 Route盒子,在Route中定义路由路径和路径对应的页面 -->
<Router>
<switch>
<Route path="/login" component={ Login }></Route>
<Route path="/home" component={ Home }></Route>
<Route path="/home/detail" exact={ true } component={ detail }></Route>
<Route path="/demo" render={ () => <div>简约写法,不需要创建页面和组件,直接路由显示render函数中定义路由页面内容即可</div>}</Route>
<!-- 简约写法,不需要创建页面和组件,直接路由显示render函数中定义路由页面内容即可 -->
</switch>
<!-- 当路由规则包裹在switch内的时,路由就不会同时显示多个,而是按照当前路径进行匹配 -->
</Router>
<!-- 路由匹配规则之,如果一个页面上同时存在 路径为 /home 和 /home/detail 两个组件,两个组件都会显示,因为 /home 是包含 /home/detail , 但是正常情况下访问 /home下的/detail是不应该显示上一级组件也就是 /home的,这个时候就需要使用到 路由规则的精准匹配, 使用 exace = { true } 即可开启精准匹配,就不会匹配到下一级路由,只会匹配到 /home 这一个, strict = { true } 可以更加精确的匹配路由,而且使用的时候strice需要和exace一起使用才可以生效,而exace不需要组合使用也可以生效 -->
<Link to="/login">go login now</Link>
<!-- Link 点击跳转到 to 后面的路由页面 -->
<NavLink to="/login" activeClassName="setActive"></NavLink>
<!-- NavLink顾名思义,导航跳转,后为当前选中的菜单导航添加一个名为active的class样式,给你这个样式添加颜色或者背景选中时便会添加该样式,activeClassName可以修改样式名称,默认是active -->
<Redirect from="/happy" to="/login"></Redirect>
<!-- Redirect可以实现路由重新向,当你访问 的地址是属性中的from,也就是要去的路由为 ‘/happy',他会直接重定向到 to所给定的路由地址 -->
</Router>
</div>
)
}
}
<!-- 处于用户体验方面的考虑,我们一般还会在路由匹配中加入 404 等页面,将不存在的路径以更友好地方式提醒用户 -->
<button>跳转</button>
<!-- 跳转的方法有 两种 props.history.push('/home') 和 props.history.replace('/home')
区别在于, push方法的页面跳转是叠加的,也就是说点击浏览器左上角的返回上一个页面依然有效,因为历史数据被保留; 而replace方法是替换的,所以不会存有历史跳转记录
-->
请到客户端“主题--自定义配置--valine”中填入ID和KEY