react总结
特点
- 声明式的设计
- 高效,采用虚拟DOM来实现DOM的渲染,最大限度的减少DOM的操作
- 灵活,跟其他库灵活搭配使用(不包括VUE)
- JSX,js代码里写HTML,JavaScript语法的拓展
- 组件化、模块化
- 单向数据流,没有实现数据的双向绑定。数据->视图->事件->数据
一、创建项目
-
安装脚手架 create react app
npm install -g create-react-app
-
创建项目
create-react-app demo(项目名称)
【补】npm run start / npm run build
二、JSX
-
优点:
(1)执行更快,框架将其编译为JavaScript代码时进行优化
(2)类型更安全,编译过程如果出错就不能编译,及时发现错误
(3)JSX编写模版更加简单快速(低于VUE)
【注意】
(1)JSX必须要有根节点(有且只有一个)
(2)正常的普通HTML元素要小写,如果大写,默认认为是组件
-
结构
(1) 由HTML元素构成
(2)中间如果需要插入变量用{}
(3){}中间可以使用表达式
(4){}中间表达式可以使用JSX对象
(5)属性和HTML内容一样都是{}来插入内容
(6)标签必须闭合
【补】
(1)在JSX中使用JavaScript表达式,表达式写在花括号{}中,
ReactDOM.render( <div> <h1>{1+1}</h1> </div>, document.getElementById('emp') )
(2)React推荐使用内联样式,我们可以使用camelCase(小驼峰)语法设置内联样式,React会在指定元素数字后自动添加px
[注]不用class,用className,因为class是js中的关键词
var myStyle = { fontSize:100, color:'#FFFFFF' } ReactDOM.render( <div> <h1 style = {myStyle}>测试内容</h1> </div> , document.getElementById('emp') )
1》class style中,不可以存在多个class属性
<div class="abc" class={'active'}></div>
2》style样式中,如果存在多个单词的属性组合,第二个单词开始,首字母大写或者用引号
borderBottom:'4px solid blue'
3》多个类作用于同一个标签时
1. <h1 className={color+" "+border}></h1> 2. let test = [color,border].join(" ") <h1 className = {test}>hello world!</h1>
(3)注释需要写在花括号中
ReactDOM.render( <div> <h1>测试内容</h1> {/*注释......*/} </div> document.getElementById('emp') )
三、组件
组件首字母要大写
静态:没有交互事件内容的多用函数式组件
动态:一般会有交互或者数据修改的多用类组件,(类组件中可以定义函数)
-
函数式组件
function HelloMessage(props){ return <h1>hello world!</h1> } const element = <HellMessage></HellMessage> ReactDOM.render( element, document.getElementById('emp') )
-
class组件
class HellOMessage extends React.Component{ render(){ return <h1>hello world!</h1> } } ReactDOM.render( <HelloMessage></HelloMessage>, document.getElementById('emp') )
-
组件间数据传递
Props-> 父传子,单向。可以为任意类型
//-------------------- 父传子(props)------------------------------ //父组件 class Parents extends React.Component{ constructor(props) { super(props) this.state={ isShow:false } this.changeShow = this.changeShow.bind(this); //changeShow写成箭头函数可以省去绑定 } changeShow(){ this.setState({ isShow:!this.state.isShow }) } render(){ //return返回JSX return( <div> <h1>我是父组件</h1> <button onClick={this.changeShow}>控制子组件是否显示</button> <Children isShow={this.state.isShow}/> </div> ) } } //子组件 class Children extends React.Component{ constructor(props) { super(props) this.state={ } } render(){ //return返回JSX console.log(this.props.isShow) let myStyle = null if(this.props.isShow){ myStyle = 'item'+' '+'active' }else{ myStyle = 'item' } return( <div className={myStyle}> <h1>我是子组件</h1> </div> ) } }
调用父元素的函数操作父元素的元素,从而实现数据从子元素传递到父元素
class Parent1 extends React.Component{ constructor(props) { super(props) this.state = { childrenMsg:null } } getMsg=(data)=>{ // console.log(this.props) console.log(data) this.setState({ childrenMsg : data }) } render(){ //return返回JSX<--用于将父元素的函数传递给子元素--> return( <div> <h1>我是子组件传递的内容:{this.state.childrenMsg}</h1> <Children1 getMsg={this.getMsg} /> </div> ) } } class Children1 extends React.Component{ constructor(props) { super(props) this.state={ message:'我是子组件内容' } } sendMsg=()=>{ console.log(this.props) // 错误 // this.setState({ // message:'我是传递内容' // }) //将子元素传递给父元素,实际就是调用父元素传递进来的父元素函数 this.props.getMsg(this.state.message) } render(){ //return返回JSX return( <div> <button onClick={this.sendMsg}>获取子组件内容</button> <button onClick={()=>{this.props.getMsg(this.state.message)}}>获取子组件内容</button> </div> ) } }
四、State
State(状态)类似于Vue的data
-
constructor(props)构造函数
如果初始化state或者不进行方法绑定,则不需要为React组件实现构造函数
其他语句之前调用super(props)
构造函数主要用于:
1》通过 this.state 赋值对象来初始化内部state。(类似于vue的data)
this.state = {count : 0};
【注】只能在构造函数中直接为 this.state 赋值,其他方法中用 this.setState({ }) 赋值
2》为事件处理函数绑定实例
this.handleClick = this.handleClick.bind(this)
constructor(props){
super(props);
this.state = {
counter: 0
};
this.handleClick = this.handleClick.bind(this)
}
-
static getDerivedStateFormProps(props, state)
在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回
null
则不更新任何内容。 -
render()方法是class组件中唯一必须实现的方法
检查 this.props 和 this.state 的变化
-
componentDidMount()组件挂载后
五、事件
-
React事件命名采用小驼峰(camelCase)
-
传入函数必须用***{}*** 括起来
-
事件对象:React返回的事件对象是代理的原生的事件对象,如果想要查看事件对象的具体值,必须直接输出事件对象的属性
<button onClick = {changeShow}>点一下</button>
【注意】
1》阻止默认行为
/*传统HTML*/ <form οnsubmit="console.log('You clicked submit.'); return false"> <button type="submit">Submit</button> </form> /* React中*/ function Form() { function handleSubmit(e) { e.preventDefault(); console.log('You clicked submit.'); } return ( <form onSubmit={handleSubmit}> <button type="submit">Submit</button> </form> ); }
2》事件传参
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
【注意】
class的方法不想在构造函数constructor中绑定解决方法
-
class fields写法(public class fields)
class LoggingButton extends React.Component { // 此语法确保 `handleClick` 内的 `this` 已被绑定。 // 注意: 这是 *实验性* 语法。 handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }
-
箭头函数
class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // 此语法确保 `handleClick` 内的 `this` 已被绑定。 return ( <button onClick={() => this.handleClick()}> Click me </button> ); } }
-
六、条件渲染
JavaScript运算符 if 条件运算符 (例如:三元运算 &&)
-
使用js中的if条件语句判断
-
与运算符(&&)
{unreadMessages.length>0 && <h2>You have {unreadMessages.length} unread messages</h2>} //因为在JavaScript中,true && expression 总是返回expression,而false && expression 总是返回 false
-
三目运算符
-
阻止组件渲染
render 方法直接返回null,不进行任何渲染
七、列表渲染
-
JSX模式
将列表内容拼装成数组放置到模版中,将数据拼装成数组的JSX对象使用***{}*** 在JSX内构建一个元素集合。使用数组的map方法,对每一项数据按照JSX的形式进行加工,最终到一个每一项都是JSX对象的数组,再将数组渲染到模板中
const numbers = [1,2,3,4,5] const listItems = numbers.map((item)=>{ return <li>{item}</li> }) ReactDOM.render( <ul>{listItem}</ul>, document.getElementById('emp') )
-
组件模式
key值需要放置到每一项中
在map方法中的元素需要设置key属性
function NumberList(props){ const numbers = props.numbers; const listItems = numbers.map(item=>{ <li key={item.toString()}>{item}</li> }) return ( <ul>{listItems}</ul> ) } const numbers = [1,2,3,4,5] ReactDOM.render( <NumberList numbers={numbers}/>, document.getElementById('emp') )
八、插槽
九、路由
安装 npm install react-router-dom
ReactRouter三大组件
-
Router:所有路由由组件的根组件(底层组件),包裹路由规则的最外层容器;
属性:basename->设置理由根路径
router->可以在一个组件中写多个
<Router> <div> <Link to="/config">ceshi</Link> </div> </Router>
-
Route:路由规则匹配组件,显示当前规则对应的组件
【注】若要精确匹配,需要在route上设置exact属性,不加就还是模糊匹配
<Route path="/config" component={Config} exact></Route>
-
Link:路由跳转的组件
(1)可以设置属性进行页面的跳转,to属性可以直接写路径的字符串,也可以通过对象进行路径的设置
{[pathname] 跳转的路径 [search] get请求的参数[state]传入的数据}
class test extends React.Component{ constructor(props){ super(props) } render(h){ let obj = {pathname:'/config',search:'123',state:true,a:'789'} return ( <Router> <div> <Link to={obj}></Link> </div> </Router> <Route path="/config" component={Config}></Route> ) } }
(2)Replace点击链接后新地址将历史记录的原地址替换,动态路由通过***props.match.params.参数*** 获取
constructor(props){ super(props) console.log(props.match.params.参数名) }
重定向组件
如果访问某组件时,有重定向组件,那么就会修改页面路径,使得页面内容显示为重定向路径的内容
<Redirect to="/about"></Redirect>
Switch组件
让switch组件内容的route只匹配一个,只要匹配到了,剩余的路由规则将不再匹配
<Switch>
<route></route>
<route></route>
</Switch>
JS实现跳转
利用history中的***push*** replace 等属性进行跳转
goToPage=(e)=>{
if(this.props.location.state){
this.props.history.push("/home")
}else{
this.props.history.push("/message/chanshu")
}
}
路由传参
-
params传参
<Link to={`/home/${name}/${age}`}></Link> <Route path="/home/:name/:age" component={home}></Route> 在home组件的props.match.params获取
-
search传参
<Link to={`/home?name=${name}&age=${age}`}></Link> <Route path="/home" component={home}></Route> import qs from 'querystring' qs.paese(this.props.location.search.slice(1))
-
state参数
<Link to="{pathname:'/home',state:{name:'123',age:18}}"></Link> <Route path="/home" component={home}></Route> this.props.location.state
withrouter
可以加工一般组件,让一般组件具备路由组件特有的API
import React,{Component} from 'react'
import {withRouter} from 'react-router-dom'
class Header extends Component{}
export default withRouter(Header)
十、状态管理 Redux
store:数据仓库,保存数据的地方
State:一个对象,数据仓库里的所有数据放到一个state里
Action:一个动作,触发数据改变的方法
Dispatch:将动作触发成方法
Reducer:一个函数,通过获取动作,改变数据,生成一个新的state,从而改变页面
-
安装
npm install redux -save
-
流程
1》初始化数据:创建一个*reducer(state={obj},action)*** 函数用于生成一个新的state(注意结构解析***{…state}***的使用),state用于存放数据,action接收dispatch传递的参数;
Reducer作用:初始化数据;通过获取动作,改变数据
const reducer = function(state={num:0},action){ switch(action.type){ case "add": state.num++; break; case "reduce": state.num--; break; } return {...state} console.log(store.getState()) }
2》创建仓库:***createStore(reducer)***,从Redux中引入
import {createStore} from 'redux' var store = createStore(reducer)
3》修改数据:创建修改函数,调用***store.dispatch({条件或名称,参数})***向render传递参数。
其实就是***store.dispatch(Action)***,Action 是一个对象。其中的
type
属性是必须的,表示 Action 的名称。其他属性可以自由设置,社区有一个规范可以参考。const add = function(){ store.dispatch({type:'add',status:1}) console.log(store.getState()) } const reduce = function(){ store.dispatch({type:'reduce',status:1}) }
4》获取数据:store.getState().name
5》修改视图:***store.subscribe()***监听数据变化
store.subscribe(()=>{ ReactDOM.render( <div> <h1>结果为{store.getState().num}</h1> <button onClick={add}>+</button> <button onClick={reduce}>-</button> </div>, document.getElementById('emp') ) } )
十一、React-redux
将所有组件分成UI组件和容器组件
-
安装
npm install react-redux -save
-
详情
1》connect() 将组件和数据(方法)进行连接
import {connect} from 'react-redux' const VisibleTodoList = connect( mapStateToProps, mapDispatchToProps )(TodoList)
VisibleTodoList是connect方法生成的容器组件,TodoList是UI组件,mapStateToProps负责输入逻辑,即将
state
映射到 UI 组件的参数(props
),mapDispatchToProps负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。2》mapStateToProps 这个函数用于将store的state映射到组件里的props
3》mapDispatchToProps 将store中的dispatch映射到组件的props里,实现方法的共享
4》Provider组件 自动将store里的state和组件进行关联
ReactDOM.render( <Provider store={store}> <TodoList></TodoList> </Provider>, document.getElementById('emp') )