先了解什么是虚拟Dom
虚拟dom就是程序员根据页面标签通过js创建dom树
之后通过新旧dom树进行对比,看dom树哪个部分变化,
从而只改变 改变的部分
- 虚拟dom本质就是用js对象来模拟dom元素和他们的嵌套关系
- 虚拟dom的目的就是为啦页面元素高效更新;也就是只更新改变的元素
- 虚拟DOM中所对比的时候用到啦diff算法;vue中也是diff
diff算法我理解大概就是,把js模拟的虚拟dom和原有的dom节点进行对比;把他们分为很多层级,每个层级和相应的层级对比;就比如一个树的最顶的树叶和另一个树的最顶的树叶对比,是一一对应的
具体解析可以看看阮一峰大神的文章
其次要懂得基本构建项目
cdn方法引入不推荐
<!-- 加载 React。-->
<!-- 注意: 部署时,将 "development.js" 替换为 "production.min.js"。-->
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
// 使用JSX
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
npm 方法安装推荐 在这之前一定要确定你已经安装node环境
cnpm install -g create-react-app // 安装react脚手架
cnpm i -g create-react-app //install可以简写为i
// 创建项目
create-react-app 项目名称
// 我这里安装出错是因为没下载cnpm包,下载并同时设置淘宝镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
注意这里可能会报错,你可以试试以管理员模式下载 mac是sudo
初步认识React
ReactDom.render()传入两个函数,第一个是对象函数,也就是dom;第二个是dom需要显示的地方
react和vue的结构大相径庭;都是有静态资源和配置文件和node依赖等等;但是react的组件是.js形式所以我们要介绍重要的组成JSX
JSX
- JSX是JavaScript XML,是React提供的Syntax Sugar, 能让我们可以在JS中写html标记语言。
- JSX会把元素转换为js对象;但是每个元素必须要有一个根元素
let h = <h1>hello word</h1> // 这是jsx语法
**let ph = <h2>hello</h2> <p>word</p>** // 会报错
let hp = <h2>hello <p>word</p></h2> // 这样是对的 只能有一个根元素
- JSX插值方法:{},{}中可以进行运算,函数,和变量
let word='hello word'
let h= <div>{word}</div>
ReactDom.render(h,
document.getelementById('root')
)
React设置样式和类名
- 设置类名是同样用插值方法,但是最好用className来设置(因为class在js中是关键字)如果有两个类名要在{}相加
//class.css 如下
.word{
width:100%;
height:200px;
background:'blue'
}
.color{
color:'red'
}
//index.js
import './class.css'
let classname='word'
let div= <div className={'color'+word} ></div>
- 在设置样式时和设置类名大相径庭,有些属性你不需要加px,react会自动帮你补全;但是backgroundColor复合单词拼成的属性,第二个单词首字母要大写;或者写成
'background-color':'red'
- 你也可以在style={}的{}中来写一个函数来判断你需要的样式也是没问题的
let backAndTextColor = {
backgroundColor:'red',
color:'white',
fontSize:40
};
{/* jsx中调用 */}
<div style={backAndTextColor}>看背景颜色和文字颜色</div>
{ /* 也可以在jsx中直接写样式,但是一定是对象格式 */ }
<div style={{backgroundColor:'red',color:'white',fontSize:40}}>看背景颜色和文字颜色</div>
React组件
- react组件分为两种:类组件和函数组件(在ReactDom.render
中,以大写字母的默认为组件) - 必须要有render () { return () } , render 中必须要有return
- 组件之间可以互相嵌套
//函数组件
function Renders(props){
console.log(props) // {hname:'哈哈哈哈'}
return (
<div> Hello Word </div>
)
}
{ /* 简单的传值 */ }
ReactDom.render(<Renders hname='哈哈哈哈' />,docment.getelementById('root'))
// 类组件
class Hello extends React.Component{
{/* 类组件必须有render函数 */}
render(){
console.log(this) {/*这里this是这个组件*/}
return(
<div>hello hi</div>
)
}
}
ReactDom.render(<Hello hi='hi' />,document.querySelector('#root'))
React state的认识
- react的state和vue的data差不多都是用来储存模版中需要改变的变量;但是他们使用方法却不一样
class Clock extends React.component{
// construtor和super可以被省略不写,或者必须写全套
constructor(props){ // es6语法 extends要配合constructor
super(props);
this.state={
word:'hello'
}
},
render(){
retrun(
<div>{this.state.word}</div>
)
}
}
ReactDom.render(<Clock />,document.querySelector('#root'))
- 当需要修改state中的变量时;需要用
setState({})
- setState是异步操作,不会立刻改变
this.state
,会等同步任务执行完,再去更新this.state
React父子组件传值
- props父组件给子组件传值,子组件不可以修改父组件穿过去的值
class Parent extends React.component{
constructor(props){
super(props);
this.state={
word:'hello'
}
},
render(){
retrun(
<Chrild word={this.state.word} />
)
}
}
ReactDom.render(<Parent />,document.querySelector('#root'))
// 子组件
class Parent extends React.component{
constructor(props){
super(props);
},
render(){
retrun(
<div>这是父组件传的值{this.props.word}</div>
)
}
}
- 可以通过传递函数来实现子组件向父组件传值
// 父组件
class Parent extends React.component{
constructor(props){
super(props);
this.state={
word:'hello'
}
},
render(){
retrun{
<Chrild word={this.changeState} />
}
}
// 也可以把下面函数改为箭头函数
this.changeState=this.changeState.bind(this)
changeState(data){
this.setState({
word:data
})
}
}
ReactDom.render(<Parent />,document.querySelector('#root'))
// 子组件
class Parent extends React.component{
constructor(props){
super(props);
this.state={
val:'888'
}
},
render(){
retrun(
<div>
这是父组件传的值{this.props.word}
<p>改变父组件的值:{this.props.changeState(this.state.val).bind(this)}</p>
</div>
)
}
}
- React事件 都是用驼峰命名法
onClick
而且react会把事件代理,你访问时需要在方法中e.event;例如阻止默认事件e.preventDefault()
- 在事件的 {} 内可以写函数
<div onClick={(e)=>{this.setState({word:e})}}>
{/* 这两种都可以 */}
<div onClick={function(e){this.setState({word:e})}}.bind(this)>
React列表渲染和判断
-
React并没有vue的v-for和v-if等指令;所以判断就是考js来完成;
-
React的列表渲染就是你请求回来的数组;这里建议通过map方法来完成;也可以根据需求去选择其他方法
React 生命周期
- 最先执行的是 construtor构造器
- 之后componentWillMount
组件被载入之前
;这里调用this.state不会引起组件重新渲染【这里的内容可以提到constructor中,所以很少使用】 - 其次是componentDidMount
组件载入完成
- 然后组件更新会使用shouldComponentupdate(nextProps, nextState)
组件是否要被更新
使用布尔值来控制是否需要继续更新;nextProps 下一个props;nextState 指下一个state ;我们可以用这个组件优化react;使其避免不必要的重复渲染
- componentWillReceiveProps(nextprops)
当组件接受到新的props时触发
;这个组件用于比较state中的值和nextprops是否一样,用不用重新赋值。 - componentWillUpdate
组件更新前
;这里render函数还未重新渲染 - 之后render函数重新渲染
- componentDidUpdate(prevProps,prevState)
组件更新完成
prevProps和prevState指组件更新前的props和state - componentWillUnmount()
组件卸载前
可以在这里清空定时器,清除挂载后手动创建的DOM,避免内存泄漏
React数据请求
React请求与vue大致一样,用axios请求就好啦;
axios中文网很细致,点击看看
React 插槽
- 在react中没有插槽组件;如果想使用需要自己动手
父组件在子组件中传入的三个div,这三个div会默认通过props传到子组件中,然后我们在子组件中控制children的渲染即可
React路由
- 首先安装路由
cnpm install react-router-dom --save
- Router标签:所有路由组件的跟组件,包裹路由规则的最外层容器
- Route标签:路由规则组件,显示当前规则对应路由
- Link标签:路由跳转组件
import {BrowserRouter as Router,Route,Link} from "react-router-dom";
<Router basename='/acs'> //basename设置此路由跟路径
// link to传放置路由路径,也可以传一个对象
<Link to={{path:'/main',seach:'?id=112'hash:'898i',state:{code:1}}}></Link>
{/* <Link to='main'></Link>*/}
// path:要跳转路径 ;exact精确模式,component:跳转的组件
<Router path='/main' exact component={Main}>
</Router>
// 之后接值需要在main组件的props
function Main(props){
return(
console.log(props.mactch) // 在macth中
)
}
- link中可以加repalce,点击链接新地址将替换原来地址
- 可以配合route标签完成动态路由
<Link to='main/123' >main</Link>
<Route path='main/:id' component={Main}></Route>
function Main(props){
return(
console.log(props.mactch.params) // 在macth的params中
)
}
- Redirect组件和Switch路由组件
import {BrowserRouter as Router,Route,Link,Switch,Redirect} from "react-router-dom";
<Redirect to='/mian'></Redirect> //路由重定向
<Router>
<Switch>
<Route path='/abc' exact component={Abc} ></Route>
<Route path='/abc' exact component={Abc} ></Route>
</Switch>
</Router>
// 如果没有switch, 即使有exact严格模式两个路由也都会执行,
// switch就是只执行一个路由
- 我们还可以通过事件来跳转路由,
this.props.history.push('/',{id:'11'})
// 跳转到某个路由()中可以传参数;这种方式是在历史中新添加一个页面this.props.history.replace('/',{id:'11'})
// 用 /替换当前页面;这种方式不会添加新页面;this.props.history.go(1)
// 前进一个页面this.props.history.go(-1)
// 后退一个页面
学习Redux
- 安装redux
cnpm install redux --save
- redux一般用于中大型项目,用来状态管理,用途解决组件互相通信;解决数据交互比较多的应用
- store:数据仓库
- state:state上一个对象;数据仓库所有数据都放在一个state里
- action:一个动作,触发数据改变的方法
action的type是必须值
- dispatch:将动作触发成功方法
- reducer:是一个函数,通过获取动作,改变数据,生成一个新的state
// createStore是Redux的一个方法,Redux.createStore也可以
import {createStore} from 'redux'
// 创建一个store ;reducer是一个函数用来改变数据
const store = createStore(reducer)
// state设置默认值,actipn是传入参数
const reducer=functiom(state={num:1},action){
...
return state // 返回新的state
}
store.dispatch({type:'add'}) //改变reducer函数的方法
store.getState() // 获取store中state数据
store.subscribe(()=>{ // store中state数据改变时调用的函数
})
React-redux
- 使用react-redux前提依然需要安装redux
- 安装react-redux
cnpm install react-redux --save
import {createStore} from 'rudux'
import {Povider,connect} from 'react-redux'
// react-redux可以使用组件props和store进行传递数据
class Mycont extends React.component{
rander(){
const value=this.props.value;
const onClickevent=this.props.onClickevent
}
}
const store=creatStore(reducer) //创建store
// ActionObj单独放需要改变state的方法 的对象
let ActionObj={
change:function(state){
state= state.toString()
return state
}
....其他方法
}
// 创建reducer函数
const reducer=function(state={},action){
state= ActionObj[action.type](action.另一个参数)
....其他操作
return {...state} // 结构方法
}
// 创建链接state和props函数;**state行参是必须**
function mapStateToProps(state){
return {
value:state.num
}
}
// 创建dispatch方法和props;**dispatch行参是必须**
function mapDispatchToProps(dispatch){
return {
onClickevent:()=>{dispatch()}
}
}
// connect作用就是将两个方法映射在需要的组件中
const App=connect(
mapStateToProps,
mapDispatchToProps,
)(Mycont) //(Mycont)是需要的组件
// Povider 组件自动将store的state和组件进行关联
ReactDom.render(
<Povider store={store}>
<App /> {/*<App></App> */}
</Provider>,
document.querySelector('#root')
)