react 入门学习笔记
安装react
npm install create-react-app 安装react脚手架
create-react-app my-app 创建项目
cd my-app
npm start
jsx jsavscript的语法扩展 就相当于javascript + html 可以在js里写html代码 具有很强的灵活性
function helloworld(){
return '<h1 class="greeting">helloworld<h1/>'
}
这就是jsx 可以在函数里生成html代码 jsx会把html代码 通过babel 转成一个dom对象。就类似于下面这样
const element = {
type: 'h1',
props: {
className: 'greeting',
children: "hello world"
}
}
这些对象被称为 react 元素 -- js对象
元素渲染
react 将一个元素渲染进dom中 会调用reactDom.render() 当元素改变时会从新调用 reactDom.render() 并只会更新改变部分
组件
react编写组件有两种方式 函数和class(类组件)
函数组件
function myComp(props) {
return <h1>hello world {props.name}<h1/>
}
class组件
class myComp extends React.Component {
constructor(props){
super(props)
}
render() {
return <h1>hello { this.props.name }</h1>
}
}
如何使用(使用组件)
function App () {
return <div>
<MyComp name="我的名字" ></MyComp>
</div>
}
使用组件是传入name到子组件,而子组件使用props.name 接受他 而props 属性只具有可读性, 不可修改
校验props 的数据类型 (propTypes) 需要引入 prop-types
import PropTypes form 'prop-type'
PropTypes.propTypes = {
name: PropTypes.string ,
age: PropTypes.number
}
function myComp(props){
return <h1>hello, {props.name}</h1>
}
myComp.defaultProps = {
name: 'World'
}
生命周期
只有类组件才具有生命周期 函数组件没有生命周期
-
挂载阶段constructor class的构造方法 -
componentWillMount 组件挂载前调用
-
render() 组件中定义的方法, 返回一个react元素, 并不负责实际渲染工作
-
componentDidMount() 组件被挂载到dom后调用, 可以在这时向后端请求数据
-
更新阶段componentWillReceiveProps(nextProps) props变化时候调用,nextProps是更新后的参数 -
shouldComponentUpdate(nextProps, nextState) // 是否继续执行更新过程
-
通过对比新值和旧值是否相同 返回false后续更新过程不在继续
-
componentWillUpdate(nextProps, nextState) 更新之前
-
render()
-
componentDidUpdate(prevProps, prevState) 组件更新之后调用
-
卸载阶段 -
componentWillUnmount() 组件被删除前调用 执行一些清理工作
state 组件可以设置自己的数据(是组件私有数据)
class myComp extends React.component {
constructor(props){
super(props)
this.state = {
time: new Date()
}
}
render(h) {
return <h1>{this.state.time}</h1>
}
}
修改state 使用setState() react自动更新子组件 setState()
事件处理
<button onClick="handelr()"></button>
react采用驼峰形式命名
this 指向问题, 在组件里使用箭头函数
class myComp extends react.Component {
constructor(props){
super(props)
this.state = {
name: 'name'
}
}
handelClick(){
console.log(this.state.name)
}
render(h) {
return <button onClick="() => this.handelClick()"></button>
}
}
这里的this 指向组件实例 这种写法每次render的时候都会创建一个新的处理函数, 如果想避免从新创建 采用下面写法
class myComp extends react.component {
constructor(props){
super(props)
this.state = {
name: "jeck"
},
this.handelClick = this.handelClick.bind(this)
}
handelClick(){
console.log(this.state.name)
}
render(h) {
return <button onClick="this.handerClick"></button>\
}
}
这样写法render 不会每次创建的时候都创建一个新的事件处理, 还可以这样
return <button onClick="this.handelClick.bind(this)"></button>
条件渲染 列表
function greet(props){
const isShow = props.isShow
if(isShow){
return <span>我是组件一</span>
}
return <span>我是组件二</span>
}
这就是react的条件渲染
列表渲染
const numbers = \[1,2,3,4,5,6]
const dataList = numbers.map((num) => <li>{num}</li>)
状态提升 就是将需要共同维护的数据提升到父组件里去
handelClick(e){
this.props.onTempPeratureChange(e.target.value)
}
//和vue this.\$emit 类似
react 16新特性 16之前 render方法必须返回单个元素 现在支持返回数组 和 字符串
class example extends React.Component {
constructor(props){
super(props)
}
render(h) {
return 'sssss'
}
}
react 16 增加了错误边界处理,如果一个组件内部发生错误 可以捕获错误 优雅的处理
class errorExtents extends react.Component {
constructor(props){
super(props)
this.state = {
isError: false
}
}
componentDidCatch(error, info){
this.setState({
isError : true
})
}
render(){
if(this.state.isError){
return <p>出错啦</p>
}
return this.props.children
}
}
使用 errorExtents
<errorExtents>
<helloworld></helloworld>
</errorExtents>
深入组件
- 直接修改state, 这样不会触发render()
- state的更新是异步的 react可能会将多次修改合并为一次更新 当调用steState()
- 的时候 React会将其标记为dirty 并将添加到事件处理队列里 然后通过合并处理来
- 更新优化, 应为是异步的当更改完就去访问值的时候可能会没有变化
组件与服务器通信,官方推荐 componentDidMount 钩子
componentDidMount(){
let that = this
fetch('/api/xxx').then( function(response){
that.setState({
data.response.data
})
})
}
组件之前的通信 (父传子) props属性 (子传父) 回调
this.props.handelClick(xxx)
子传父 通过props调用父组件方法
<child handelClick={this.handelClick}></chlid>
Context 组件层级太深 props 会很繁琐 可以使用Content
getChildContent(){
return { handleClick: this.handleClick}
}
Father.childContextTypes = {
handleClick: propTypes.func
}
子组件通过context访问
this.context.handleClick()
Child.contextTypes = {
handleClick: Propstypes.func
}
使用ref 获取dom
<input type="text" ref = { (input) => { this.textInput = input}}></input>
this.textInput.focus()
在组件上使用 只能是类组件
高阶组件 HOC
高阶组件是以函数为参数, 返回值也是函数的函数 高阶组件只需关注抽象的逻辑, 无需关注页面ui/dom, 可以使用高阶组件 数据校验 请求 当多个组件有相同的逻辑的时
function HocComp(comp){
return class extends React.Component {
componentWillMount(){
let data = localStorage.getItem('data')
this.setState({data})
}
render (){
return \<comp data={this.state.data} {...this.props}><comp/>
}
}
}
class myComp extends React.Component{
render(){
return <duv>{this.props.data}</duv>
}
}
const myCompWith = HocComp(myComp)
上面可以看出高阶组件可以 封装并分离组件通用逻辑, 让逻辑在组件中更好的被复用
使用场景 操作props
function HocRef(warpComp){
return class extends React.Component {
constructor(props){
super(props)
this.someMenten = this.someMenten.bind(this)
}
someMenten(){
this.instance.menthofWarpper()
}
render(){
return <warpComp ref={ (instance) => this.instance = instance } ></warpComp>
}
}
}
react Router
react router 包含了3个库 react-router, react-router-dom react-router-natiive react router 通过router 和 route 两个组件完成路由功能 import { Route } from 'react-router'
<Route path="/"></Route>
<Route path="/" component = {Home}></Route>
<Route path="/" render = {
(props) => {
<Home { ... props }></Home>
}
}></Route>
如果想匹配到一个路由可以
import { Router, Switch, Route , Link } from 'react-router-dom'
<Router>
<Switch>
<Route path="/" component= { Home }></Route>
<Route path="/about" component= { About }></Route>
<Route path="/user" component= { User }></Route>
</Switch>
</Router>
重定向 <Redirect to = { xxx }
link 定义了如何路由
<link to="/login"><link/>
<Link to = {{
pathname:"/login",
stateL {isLogin: false}
}}
withRouter
import react from 'react'
import { withRouter } from 'react-router-dom'
function backBtn(props){
let { history } = props
return <button onClick= { () =>{
history.gobac
k()
}}></button>
}
backBtn = withRouter(backBtn)
export default backBtn