React 构建用户界面的JavaScript库,主要用于构建UI界面。Instagram,2013年开源。javascript
1、经过script引入使用,仅用于学习调试使用css
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
二、经过react的脚手架,建立项目进行开发,部署html
1. 安装脚手架Create React App。 cnpm install -g create-react-app 2. 建立项目 create-react-app 01reactapp(项目名称能够自定义)
let h1 = <h1>helloworld</h1>; 使用JSX的写法,能够建立JS元素对象 注意:JSX元素对象,或者组件对象,必须只有1个根元素(根节点)
案例使用:vue
//实现页面时刻的显示 function clock(){ let time = new Date().toLocaleTimeString() let element = ( <div> <h1>如今的时间是{time} </h1> <h2>这是副标题</h2> </div> ) let root = document.querySelector('#root'); ReactDOM.render(element,root) } clock() setInterval(clock,1000)
函数式组件渲染java
function Clock(props){ return ( <div> <h1>如今的时间是{props.date.toLocaleTimeString()} </h1> <h2>这是函数式组件开发</h2> </div> ) } function run(){ ReactDOM.render( <Clock date={new Date()} />, document.querySelector('#root') ) } setInterval(run,1000)
优势:react
注意:es6
案例vuex
import React from 'react'; import ReactDOM from 'react-dom'; import './App.css' let time = new Date().toLocaleTimeString() let str = '当前时间是:' let element = ( <div> <h1>helloworld</h1> <h2>{str+time}</h2> </div> ) console.log(element) let man = '发热'; let element2 = ( <div> <h1>今天是否隔离</h1> <h2>{man=="发热"?<button>隔离</button>:"躺床上"}</h2> </div> ) //let man = '发热'; let element4 = ( <div> <span>横着躺</span> <span>竖着躺</span> </div> ) man = '正常' let element3 = ( <div> <h1>今天是否隔离</h1> <h2>{man=="发热"?<button>隔离</button>:element4}</h2> </div> ) let color = 'bgRed' let logo = 'https://www.baidu.com/img/pc_1c6e30772d5e4103103bd460913332f9.png' //HTML的样式类名要写className,由于class在js当中是关键词 let element5 = ( <div className={color}> <img src={logo} /> 红色的背景颜色 </div> ) ReactDOM.render( element5, document.getElementById('root') )
let exampleStyle = { background:"skyblue", borderBottom:"4px solid red", 'background-image':"url(https://www.baidu.com/img/pc_1c6e30772d5e4103103bd460913332f9.png)" }
3.多个类共存的操做npm
let element2 = ( <div> <h1 className={"abc "+classStr}>helloworld</h1> </div> ) let classStr2 = ['abc2','redBg2'].join(" ") let element3 = ( <div> {/* 这里写注释 */} <h1 className={classStr2} style={exampleStyle}>helloworld</h1> </div> )
4.注释json
必须在括号的表达式内书写,不然报错:{/* 这里写注释 */}
函数式组件与类组件的区别和使用,函数式比较简单,通常用于静态没有交互事件内容的组件页面。类组件,通常又称为动态组件,那么通常会有交互或者数据修改的操做。
//函数式组件 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{ render(){ console.log(this) return ( <div> <h1>类组件定义HELLOWORLD</h1> <h1>hello:{this.props.name}</h1> <Childcom weather={this.props.weather} /> </div> ) } }
3.复合组件:组件中又有其余的组件,复合组件中既能够有类组件又能够有函数组件。
import React from 'react'; import ReactDOM from 'react-dom'; import './04style.css'; //函数式组件 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> ) } //类组件定义 class HelloWorld extends React.Component{ render(){ console.log(this) //返回的都是JSX对象 return ( <div> <h1>类组件定义HELLOWORLD</h1> <h1>hello:{this.props.name}</h1> <Childcom weather={this.props.weather} /> </div> ) } } // ReactDOM.render( // <Childcom weather="出太阳" />, // document.querySelector('#root') // ) ReactDOM.render( <HelloWorld name="老陈" weather="下雨" />, document.querySelector('#root') )
至关于VUE的DATA,可是使用方式跟VUE不一致。
父传递给子组件数据,单向流动,不能子传递给父。
props的传值,能够是任意的类型。
Props能够设置默认值
HelloMessage.defaultProps = { name:”老陈”,msg:“helloworld” }
注意:props能够传递函数,props能够传递父元素的函数,就能够去修改父元素的state,从而达到传递数据给父元素。
父传参给子
//在父元素中使用state去控制子元素props的从而达到父元素数据传递给子元素 class ParentCom extends React.Component{ constructor(props){ super(props) this.state = { isActive:true } //绑定事件 this.changeShow = this.changeShow.bind(this) } render(){ return ( <div> <button onClick={this.changeShow}>控制子元素显示</button> <ChildCom isActive={this.state.isActive} /> </div> ) } changeShow(){ this.setState({ isActive:!this.state.isActive }) } } class ChildCom extends React.Component{ constructor(props){ super(props) } render(){ let strClass = null; if(this.props.isActive){ strClass = ' active' }else{ strClass = "" } strClass = this.props.isActive?" active":""; return ( <div className={"content"+strClass}> <h1>我是子元素</h1> </div> ) } }
子传参给父
class Parent extends React.Component { constructor(props) { super(props) this.state = { childData: null } } render() { return ( <div> <h1>子元素传递给父元素的数据:{this.state.childData}</h1> {/* 将设置参数的方法经过props传给子元素 */} <Child setChildData={this.setChildData}/> </div> ) } setChildData=(data)=>{ this.setState({ childData:data }) } } class Child extends React.Component{ constructor(props){ super(props) this.state={ msg:"helloworld" } } render(){ return( <div> <button onClick={this.senData}>传参给父元素</button> //使用ES6,能够直接在按钮的事件中写箭头函数传参 <button onClick={()=>{this.props.setChildData("666")}}>传参给父元素</button> //不使用ES6, <button onClick={function(e){this.props.setChildData("666")}.bind(this)}>传参给父元素</button> </div> ) } //不绑定事件能够直接使用箭头函数 senData=()=>{ 从父元素传过来的props里面的方法传递参数 this.props.setChildData(this.state.msg) } }
事件
特色:
一、react事件,绑定事件的命名,驼峰命名法。
二、{},传入1个函数,而不是字符串
<button onClick={this.sendData}>传递helloworld给父元素</button>
事件对象:React返回的事件对象是代理的原生的事件对象,若是想要查看事件对象的具体值,必须之间输出事件对象的属性。
注意:
原生,阻止默认行为时,能够直接返回return false;
React中,阻止默认必须e.preventDefault();
React事件传参数
{/* 使用ES6箭头函数传递多个参数 */} <button onClick={(e)=>{this.parentEvent1('msg:helloworld',e)}}>提交</button> {/* //不使用ES6箭头函数传递多个参数的方式 */} <button onClick={function(e){this.parentEvent1('不使用es6,msg:helloworld',e)}.bind(this)}>提交</button>
条件渲染
一、直接经过条件运算返回要渲染的JSX对象
二、经过条件运算得出jsx对象,在将JSX对象渲染到模板中。
案例1
function UserGreet(props){ return (<h1>欢迎登录</h1>) } function UserLogin(props){ return (<h1>请先登陆</h1>) } class ParentCom extends React.Component{ constructor(props){ super(props) this.state = { isLogin:true } } render(){ if(this.state.isLogin){ return (<UserGreet></UserGreet>) }else{ return (<UserLogin></UserLogin>) } } }
案例2
function UserGreet(props){ return (<h1>欢迎登录</h1>) } function UserLogin(props){ return (<h1>请先登陆</h1>) } class ParentCom extends React.Component{ constructor(props){ super(props) this.state = { isLogin:false } } render(){ let element = null; if(this.state.isLogin){ element = <UserGreet></UserGreet>; }else{ element = (<UserLogin></UserLogin>); } return ( <div> <h1>这是头部</h1> {element} <h1>这是三元运算符的操做</h1> {this.state.isLogin?<UserGreet></UserGreet>:<UserLogin></UserLogin>} <h1>这是尾部</h1> </div> ) } }
列表渲染
将列表内容拼装成数组放置到模板中。将数据拼装成数组的JSX对象。
使用数组的map方法,对每一项数据按照JSX的形式进行加工,最终获得1个每一项都是JSX对象的数组,在将数组渲染到模板中。
Key值须要放置到每一项中。
案例1
class Welcome extends React.Component{ constructor(props){ super(props) this.state = { list:[ { title:"第一节 React事件", content:"事件内容" }, { title:"第二节 React数据传递", content:"数据传递内容", }, { title:"第三节 条件渲染", content:"条件渲染内容", } ] } } render(){ let listArr = []; for(let i=0;i<this.state.list.length;i++){ let item = ( <li> <h3>{this.state.list[i].title}</h3> <p>{this.state.list[i].content}</p> </li> ) listArr.push(item) } return ( <div> <h1> 今天课程内容 </h1> <ul> {listArr} <li> <h3>这是标题</h3> <p>内容</p> </li> </ul> </div> ) } }
案例2
function ListItem(props){ return ( <li> <h3>{props.index+1}:listItem:{props.data.title}</h3> <p>{props.data.content}</p> </li> ) } class ListItem2 extends React.Component{ constructor(props){ super(props) } render(){ return ( <li onClick={(event)=>{this.clickEvent( this.props.index, this.props.data.title, event )}}> <h3>{this.props.index+1}:listItem:{this.props.data.title}</h3> <p>{this.props.data.content}</p> </li> ) } clickEvent=(index,title,event)=>{ alert((index+1)+"-"+title) } } class Welcome extends React.Component{ constructor(props){ super(props) this.state = { list:[ { title:"第一节 React事件", content:"事件内容" }, { title:"第二节 React数据传递", content:"数据传递内容", }, { title:"第三节 条件渲染", content:"条件渲染内容", } ] } } render(){ let listArr = this.state.list.map((item,index)=>{ return ( <ListItem2 key={index} data={item} index={index}></ListItem2> ) }) return ( <div> <h1> 今天课程内容 </h1> <ul> {listArr} <li> <h3>这是标题</h3> <p>内容</p> </li> </ul> <h1>复杂没有用组件完成列表</h1> <ul> { this.state.list.map((item,index)=>{ return ( <li key={index} onClick={(event)=>{this.clickFn(index,item.title,event)}}> <h3>{index+1}-复杂-{item.title}</h3> <p>{item.content}</p> </li> ) }) } </ul> </div> ) } clickFn=(index,title,event)=>{ alert((index+1)+"-clickFn-"+title) } }
生命周期便是组件从实例化到渲染到最终从页面中销毁,整个过程就是生命周期,在这生命周期中,咱们有许多能够调用的事件,也俗称为钩子函数
生命周期的3个状态:
Mounting:将组件插入到DOM中
Updating:将数据更新到DOM中
Unmounting:将组件移除DOM中
生命周期中的钩子函数(方法,事件)
CompontWillMount :组件将要渲染,AJAX,添加动画前的类
CompontDidMount:组件渲染完毕,添加动画
compontWillReceiveProps:组件将要接受props数据,查看接收props的数据什么
ShouldComponentUpdate:组件接收到新的state或者props,判断是否更新。返回布尔值
CompontWillUpdate:组件将要更新
ComponentDidUpdate:组件已经更新
ComponentwillUnmount:组件将要卸载
组建中写入内容,这些内容能够被识别和控制。React须要本身开发支持插槽功能。
原理:
组件中写入的HTML,能够传入到props中。
组件中的HTML内容直接所有插入
组件中的HTML内容直接所有插入
class ParentCom extends React.Component{ render(){ console.log(this.props) return ( <div> <h1>组件插槽</h1> {this.props.children} </div> ) } }
组件中根据HTML内容的不一样,插入的位置不一样。
import React from 'react'; import ReactDOM from 'react-dom'; class ParentCom extends React.Component{ render(){ console.log(this.props) return ( <div> <h1>组件插槽</h1> {this.props.children} <ChildCom> <h1 data-position="header">这是放置到头部的内容</h1> <h1 data-position="main">这是放置到主要的内容</h1> <h1 data-position="footer">这是放置到尾部的内容</h1> </ChildCom> </div> ) } } class ChildCom extends React.Component{ render(){ let headerCom,mainCom,footerCom; this.props.children.forEach((item,index)=>{ if(item.props['data-position']==='header'){ headerCom = item }else if(item.props['data-position']==='main'){ mainCom = item }else{ footerCom = item } }) return ( <div> <div className="header"> {headerCom} </div> <div className="main"> {mainCom} </div> <div className="footer"> {footerCom} </div> </div> ) } } class RootCom extends React.Component{ constructor(props){ super(props) //console.log(props) this.state = { arr:[1,2,3] } } render(){ return ( <ParentCom> <h2 data-name="a" data-index={this.state.arr[0]}>子组件1</h2> <h2 data-name="b" data-index={this.state.arr[1]}>子组件2</h2> <h2 data-name="c" data-index={this.state.arr[2]}>子组件3</h2> </ParentCom> ) } } ReactDOM.render( <RootCom></RootCom> , document.querySelector("#root") )
根据不一样的路径,显示不一样的组件(内容);React使用的库react-router-dom;
安装
Cnpm 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="/admin/" exact component={Home}></Route> <Route path="/admin/product" component={Product}></Route> <Route path="/admin/me" exact component={Me}></Route> </Router> </div> ) } } export default App
Link组件能够设置to属性来进行页面的跳转,to属性能够直接写路径的字符串,也能够经过1个对象,进行路径的设置,如
render(){ let meObj = { pathname:"/me",//跳转的路径 search:"?username=admin",//get请求参数 hash:"#abc",//设置的HASH值 state:{msg:'helloworld'}//传入组件的数据 }; return ( <div id="app"> <Router> <div className="nav"> <Link to="/">Home</Link> <Link to="/product">Product</Link> <Link to={ meObj }>我的中心</Link> </div> <Route path="/" exact component={Home}></Route> <Route path="/product" component={Product}></Route> <Route path="/me" exact component={Me}></Route> </Router> </div> ) }
Link的replace属性:点击连接后,将新地址替换成历史访问记录的原地址。
动态路由实现:
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(props){ console.log(props) return ( <div> <h1>admin我的中心</h1> </div> ) } function Product(){ return ( <div> <h1>admin产品页面</h1> </div> ) } function News(props){ console.log(props) return ( <div> 新闻页,新闻id:{props.match.params.id} </div> ) } class App extends React.Component{ render(){ let meObj = { pathname:"/me",//跳转的路径 search:"?username=admin",//get请求参数 hash:"#abc",//设置的HASH值 state:{msg:'helloworld'}//传入组件的数据 }; return ( <div id="app"> <Router> <div className="nav"> <Link to="/">Home</Link> <Link to="/product">Product</Link> <Link to={ meObj } replace>我的中心</Link> <Link to="/news/4568789">新闻页</Link> </div> <Route path="/" exact component={Home}></Route> <Route path="/product" component={Product}></Route> <Route path="/me" exact component={Me}></Route> <Route path="/news/:id" component={News}></Route> </Router> </div> ) } } export default App
若是访问某个组件时,若是有重定向组件,那么就会修改页面路径,使得页面内容显示为所定向路径的内容
用例:
function LoginInfo(props){ //props.loginState = 'success'; //props.loginState = "fail" console.log(props) if(props.location.state.loginState === 'success'){ return <Redirect to="/admin"></Redirect> }else{ return <Redirect to="/login"></Redirect> } }
让switch组件内容的route只匹配1个,只要匹配到了,剩余的路由规则将再也不匹配
class App extends React.Component{ render(){ return ( <div> <Router> <Switch> <Route path="/" exact component={()=>(<h1>首页</h1>)}></Route> <Route path="/form" exact component={FormCom}></Route> <Route path="/login" exact component={()=>(<h1>登陆页</h1>)}></Route> <Route path="/logininfo" exact component={LoginInfo}></Route> <Route path="/admin" exact component={()=>(<h1>admin页,登陆成功</h1>)}></Route> <Route path="/abc" exact component={()=>(<h1>abc1页,登陆成功</h1>)}></Route> <Route path="/abc" exact component={()=>(<h1>abc2页,登陆成功</h1>)}></Route> </Switch> </Router> </div> ) } }
解决React数据管理(状态管理),用于中大型,数据比较庞大,组件之间数据交互多的状况下使用。若是你不知道是否须要使用Redux,那么你就不须要用它!
* 解决组件的数据通讯。
* 解决数据和交互较多的应用
Redux只是一种状态管理的解决方案!
Store:数据仓库,保存数据的地方。
State:state是1个对象,数据仓库里的全部数据都放到1个state里。
Action:1个动做,触发数据改变的方法。
Dispatch:将动做触发成方法
Reducer:是1个函数,经过获取动做,改变数据,生成1个新state。从而改变页面
安装
Cnpm install redux --save
初始化数据
//建立仓库 const store = createStore(reducer) //用于经过动做,建立新的state //reduce有2个做用,1初始化数据,第二个就是经过获取动做,改变数据 const reducer = function(state={num:0},action){ console.log(action) switch(action.type){ case "add": state.num++; break; case 'decrement': state.num--; break; default: break; } return {...state}//至关于对象的COPY }
获取数据
let state = store.getState()
修改数据(经过动做修改数据)
//经过仓库的方法dispatch进行修改数据 store.dispatch({type:"add",content:{id:1,msg:"helloworld"}})
修改视图(监听数据的变化,从新渲染内容)
store.subscribe(()=>{ ReactDOM.render(<Counter></Counter>,document.querySelector("#root")) })
完整案例
import React from 'react'; import ReactDOM from 'react-dom'; import {createStore} from 'redux' //用于经过动做,建立新的state const reducer = function(state={num:0},action){ console.log(action) switch(action.type){ case "add": state.num++; break; case 'decrement': state.num--; break; default: break; } return {...state}//至关于对象的COPY } //建立仓库 const store = createStore(reducer) console.log(store) function add(){ //经过仓库的方法dispatch进行修改数据 store.dispatch({type:"add",content:{id:1,msg:"helloworld"}}) console.log(store.getState()) } function decrement(){ //经过仓库的方法dispatch进行修改数据 store.dispatch({type:"decrement"}) console.log(store.getState()) } //函数式计数器 const Counter = function(props){ //console.log(store.getState()) let state = store.getState() return ( <div> <h1>计数数量:{state.num}</h1> <button onClick={add}>计数+1</button> <button onClick={decrement}>计数-1</button> </div> ) } ReactDOM.render(<Counter></Counter>,document.querySelector("#root")) store.subscribe(()=>{ ReactDOM.render(<Counter></Counter>,document.querySelector("#root")) })
安装
cnpm install react-redux --save
概念:
Provider组件:自动的将store里的state和组件进行关联。
MapStatetoProps:这个函数用于将store的state映射到组件的里props
mapdispatchToProps:将store中的dispatch映射到组件的props里,实现了方法的共享。
Connect方法:将组件和数据(方法)进行链接
使用:
初始化数据,实例化store
function reducer(state={num:0},action){ switch(action.type){ case "add": state.num++; break; default: break; } return {...state} } const store = createStore(reducer)
数据的获取,数据的修改
要state映射到到组件的props中,将修改数据的方法映射到组件的props中
完整案例
import React from 'react'; import ReactDOM from 'react-dom'; import {createStore} from 'redux'; import {connect, Provider} from 'react-redux' class Counter extends React.Component{ render(){ console.log(this.props) //计数,经过stroe的state传给props,直接经过props就能够将state的数据获取 const value = this.props.value; //将修改数据的事件或者方法传入到props const onAddClick = this.props.onAddClick; //等同于vuex的mapMutation mapState return ( <div> <h1>计数的数量:{value}</h1> <button onClick={onAddClick}>数字+1</button> <button onClick={this.props.onAddClick5}>数字+5</button> </div> ) } } let ActionFnObj={ add:function(state,action){ state.num++ return state }, addNum:function(state,action){ state.num = state.num + action.num; return state } } function reducer(state={num:0},action){ if(action.type.indexOf('redux')===-1){ state = ActionFnObj[action.type](state,action) return {...state} }else{ return state; } } const store = createStore(reducer) //将state映射到props函数 function mapStateToProps(state){ return { value:state.num } } const addAction = { type:'add' } //将修改state数据的方法,映射到props,默认会传入store里的dispach方法 function mapDispatchToProps(dispatch){ return { onAddClick:()=>{dispatch(addAction)}, onAddClick5:()=>{dispatch({type:"addNum",num:5})} } } //将上面的这2个方法,将数据仓库的state和修改state的方法映射到组件上,造成新的组件。 const App = connect( mapStateToProps, mapDispatchToProps )(Counter) ReactDOM.render( <Provider store={store}> <App></App> </Provider>, document.querySelector("#root") )
npm install antd-mobile --save
按须要导入(自动导入用到的css样式):
npm install babel-plugin-import --save
2.配置
npm run eject
3.Packjson文件
"babel": { "presets": [ "react-app" ], "plugins": [ ["import", { "libraryName": "antd-mobile", "style": "css" }] ] }
其他参考官网