0%

React学习笔记

创建项目

  • 通过 create-react-app 进行创建
npx create-react-app demo
  • 通过 umi 进行创建
yarn create umi

绑定事件

import React, {Component} from 'react'
import ReactDom from 'react-dom'

// 组件名,也就是类名,必须是大写开头
class HeaderDom extends Component {
this.state = {
name: '黄某人',
age: 18
}

handleClick1(){
console.log('触发了点击事件');
}

handleClick2(){
console.log(this.state.name)
}

render() {
// 绑定其他事件也是同理,on+事件名
<div>
<button onClick={this.handleClick1}>触发点击事件</button>
<button onClick={this.handleClick2.bind(this)}>触发点击事件</button>
<div/>
}
}
  • 组件名称必须是大写
  • 如果事件函数里需要用到this,则在设置事件的时候,需要使用bind绑定this指向

state

state在react中是用来保存组件状态的数据的,类似于vue中的data

获取state

console.log(this.state.xxx);

设置state

this.setState({
key: val
})

组件传参

import React, { Component } from 'react'
import '../src/assets/css/app1.css'


// 这是子组件
class HeaderDom extends Component {
render() {
return (
<header>
<ul className="nav-list">
{
this.props.navList.map((nav) => (
<li key={nav.link} title={nav.txt}>{nav.txt}</li>
))
}
</ul>
<h3>
{this.props.children}
</h3>
</header>
)
}
}

// 这是父组件
export default class App1 extends Component {

constructor(props) {
super(props)

this.state = {
navList: [
{ txt: '首页', link: '/' },
{ txt: '商品', link: '/goods' },
{ txt: '发现', link: '/faxian' },
{ txt: '社区', link: '/shequ' },
{ txt: '我的', link: '/me' },
]
}
}

render() {
return (
<div>
<HeaderDom navList={this.state.navList}>这是children的内容</HeaderDom>
</div>
)
}
}

  • 父组件通过标签属性的方式传递数据给子组件
  • 子组件里通过 this.props.xxx 获取父组件传递过来的参数
  • 子组件可通过 this.props.children 获取到标签的内容

props默认值

假如父组件没有传递某些参数给子组件,那么子组件可以这些数据定义一个默认值

import React, { Component } from 'react'
import '../src/assets/css/app1.css'


class HeaderDom extends Component {
// 设置props默认值,static defaultProps 是固定写法,不是随便乱写的
static defaultProps = {
navList: [
{ txt: '首页1', link: '/' },
{ txt: '商品2', link: '/goods' },
{ txt: '发现3', link: '/faxian' },
{ txt: '社区4', link: '/shequ' },
{ txt: '我的5', link: '/me' },
]
}

render() {
return (
<header>
<ul className="nav-list">
{
this.props.navList.map((nav) => (
<li key={nav.link} title={nav.txt}>{nav.txt}</li>
))
}
</ul>
</header>
)
}
}

export default class App1 extends Component {
render() {
return (
<div>
<HeaderDom navList={this.state.navList} />
</div>
)
}
}

  • props的默认值必须在子组件里进行设置
  • static defaultProps 是固定语法,不能乱写

验证props有效性

验证props参数的合法性,需要安装一个插件

cnpm i prop-types

示例代码:

import React, { Component } from 'react'
// 导入验证props的功能模块
import PropTypes from 'prop-types'


class Children extends Component {
// static propTypes 是固定写法,不能随意改变
static propTypes = {
// 要验证的字段:PropTypes.验证类型
title: PropTypes.string
}

render() {
return (
<h1>{this.props.title}</h1>
)
}
}


export default class App1 extends Component {

constructor(props) {
super(props)
this.state = {
title: '我是黄某人'
}
}

render() {
return (
<div>
<Children title={this.state.title} />
</div>
)
}
}


context传参

示例代码:

import React, { Component } from 'react'
import PropTypes from 'prop-types'



class Children extends Component {

// 要接收的数据的类型
static contextTypes = {
title: PropTypes.string
}

render() {
return (
// 通过 this.context 来取出数据
<span>{this.context.title}</span>
)
}
}



class Child extends Component {
render() {
return (
<h1>
<Children />
</h1>
)
}
}


export default class App1 extends Component {

constructor(props) {
super(props)
this.state = {
title: '我是黄某人'
}
}


// 要传递给其他组件的数据的类型
static childContextTypes = {
title: PropTypes.string
}

// 要传递给其他组件的数据
getChildContext() {
return {
title: this.state.title
}
}

render() {
return (
<div>
<Child />
</div>
)
}
}

  • 发送方,要写 static childContextTypesgetChildContext
  • 接收方要写 contextTypes
  • 接收方要通过 this.context.xxx 来取出数据
  • 参考 https://zh-hans.reactjs.org/docs/context.html

子传父

  1. 父类将自己身上的某个方法传递给子类
  2. 子类通过 this.props.xxx() 来得到这个方法
  3. 当子类被触发某个事件的时候,子类主动去调用这个父类传递过来的方法
  4. 如果需要传递参数给父类,则通过子类传递实参,父类通过回调函数的形参接收

示例代码:

import React, { Component } from 'react'

class Child extends Component {
handleClick() {
// 调用父类传递过来的方法,并传递要传递的参数
this.props.fatherMethod(66);
}
render() {
return (
// 子类给标签绑定事件处理函数
<button onClick={this.handleClick.bind(this)}>点击</button>
)
}
}


export default class App1 extends Component {

constructor(props) {
super(props)
this.state = {
title: '我是黄某人'
}
}

// 定义要传递给子类的方法
fatherMethod(title) {
this.setState({
title
})
}

render() {
return (
<div>
// 通过标签属性的方式,向子类传递这个方法
<Child fatherMethod={this.fatherMethod.bind(this)} />
<p>{this.state.title}</p>
</div>
)
}
}


生命周期

挂载阶段

  • constructor:初始化组件
  • UNSAFE_compomentWillMount:数据挂载前
  • render:渲染页面
  • componentDidMount:数据挂载后,一般在这发ajax

更新阶段

  • props更新
    • UNSAFE_componentWillReceiveProps:接收props前
  • state更新
    • shouldComponentUpdate:可以得到修改前后的值,可选择是否重新渲染,return true 渲染,return false 不渲染
    • UNSAFE_componentWillUpdate:更新前
    • componentDidUpdate:更新后

卸载期

  • componentWillUnmount:页面或组件被卸载前

受控和不受控组件

  • 受控组件:绑定有 state 数据和 onChange 事件等,常用在表单元素上

  • 不受控组件:采用 refthis.refs.xxx 来处理


路由

依赖插件:cnpm i react-router-dom

hash路由使用方式:

import ReactDom from 'react-dom'
// 导入路由模块
import { HashRouter, Route } from 'react-router-dom'

import App from './router/App.jsx'
import Index from './router/Index.jsx'
import List from './router/List.jsx'

// 声明路由对象
let router = <HashRouter>
{/* 配置路由规则 */}
<Route path="/" exact component={App}></Route>
<Route path="/index" exact component={Index}></Route>
<Route path="/list" exact component={List}></Route>
</HashRouter>

// 渲染路由对象
ReactDom.render(router, document.getElementById('root'))
  • 导入 HashRouterRoute
  • 导入页面组件
  • 声明路由对象
  • 配置路由规则
  • 渲染路由对象

路由传参

发送方:

<a href="#/app/list/189">跳转</a>

<Route path="/app/list/:listId"/>

接收方:

<p>
{this.props.routeParams.listId}
</p>

嵌套路由

import React, { Component } from 'react'

import { HashRouter as Router, Route, Redirect } from 'react-router-dom'

import Index from './Index.jsx'
import List from './List.jsx'

class App extends Component {
render() {
return (
<div>
<ul style={{ display: "flex", justifyContent: "center", listStyle: "none" }}>
<li style={{ marginRight: 20 }}><a href="#/app/index"> 首页 </a></li>
<li style={{ marginRight: 20 }}><a href="#/app/list"> 列表页 </a></li>
</ul>
<div style={{ margin: "0 auto", width: 1200, height: 500, border: "2px solid red" }}>
{/* 这是二级路由页面存放位置 */}
<Route path="/app/index" exact component={Index} />
<Route path="/app/list" exact component={List} />
</div>
</div>
)
}
}


// 配置路由对象
let router =
<Router>
<div>
{/* 重定向到首页的路径 */}
<Redirect from="/" to="/app/index" component={Index}></Redirect>
{/* 一级路由 */}
<Route path="/app" component={App}></Route>
</div>
</Router>


// 导出这个路由对象,然后 由 ReactDom.render 进行渲染
export default router

  • 注意点:<Route> 这里不能写任何东西,否则路由失效 </Route>

常见问题

  • 执行 yarn eject 后报错 React is not defined
  • 原因:jsx 运行时的 webpack 配置会在 eject 时候被删除,所以需要在 package.json 把配置加回来
{
"babel": {
"presets": [
[
"react-app",
{
"runtime": "automatic"
}
]
]
}
}
  • antd-mobile 的按钮组件连续点击会报错
body {
touch-active: pan-y;
}
  • 使用 react-mobileCarousel 滑动时报错 Unable to preventDefault inside passive event listene
  • 原因:
/* 给html标签或相关元素添加 pan-y 或 none */
html {
touch-active: pan-y;
}

Hooks

  • useState

作用:让函数组件也有自己的state

用法:

import {useState} from 'react'

const Demo = () => {
const [name, setName] = useState('黄某人');
return (<div>{name}</div>)
}
  • useEffect

作用:类似于 componentDidMountcomponentDidUpdate

用法:

import {useState} from 'react'

const Demo = () => {
useEffect(() => {
console.log('页面加载完成执行,数据更新时也执行')
})
return (<div>666</div>)
}

useStateuseEffect 在组件内可以定义多个


react-redux的用法

  1. 新建 reducers 文件夹,并在里面创建 index.js 文件

  2. 然后再 reducers 文件夹内创建别的文件夹或文件,根据自己的需要,例如创建 blog.js

  3. blog.js 的内容如下:

    // state 的初始值
    const initState = {
    list: [
    {userId: 1, title: '测试标题', body: '测试内容'},
    {userId: 2, title: '测试标题', body: '测试内容'},
    ],
    isLoading: false
    };

    export default (state = initState, action) => {
    switch(action.type) {
    default:
    return state;
    }
    }
  4. index.js 里导入我们刚刚创建的好的 blog.js

    import { combineReducers } from 'redux'
    import blog from './blog'
    export default combineReducers({
    blog
    })
  5. src 目录下新建 store.js ,内容如下

    import { createStore, applyMiddleware } from 'redux'
    import reducers from './reducers/index'
    import thunk from 'redux-thunk'
    export default createStore(
    reducers,
    applyMiddleware(thunk)
    )
  6. 打开 src/index.js 入口文件,内容如下

    import react from 'react'
    import { render } from 'react-dom'
    import { provider } from 'react-redux'
    import App from './App'
    import store from './store'

    render(
    <provider store={store}>
    <App/>
    </provider>,
    document.getElementById('root')
    )
  7. 新建一个页面组件,假设内容如下

    import react, {Component} from 'react'
    import {connect} from 'react-redux'

    class Blog extends Component {
    console.log(this.props)
    const {list, isLoading} = this.props;
    render(){
    return (
    <>
    {
    isLoading ?
    <div> loading··· </div>
    :
    this.props.list.map(item=>{
    return (
    <h1>{item.title}</h1>
    <p>{item.body}</p>
    )
    })
    }
    </>
    )
    }
    }

    const mapState = state => ({
    list: state.blog.list
    })

    export default connect(mapState)(Blog)
-------------本文结束    感谢阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!