Skip to content

react基础笔记

react基础学习记录
javascript
// 根组件的组件定义
//cnpm install react-router-dom --save 安装react路由
//cnpm install redux --save 安装react数据仓库
//cnpm install react-redux --save 安装react数据仓库
// 可以使用ant ui组件库
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
// 这里获取App即根组件
import * as serviceWorker from './serviceWorker'

// import {HashRouter as Router,Link,Route} from 'react-router-dom'
//以哈希模式导入路由
import { BrowserRouter as Router, Link, Route, Redirect, Switch } from 'react-router-dom'
//以history模式导入路由

import { createStore } from 'redux'
// 安装Redux后调用
import { Provider, connect } from 'react-redux'

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
下面是函数式组件基础
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// let app = <App />
// // jsx存储组件
// let time = new Date().toDateString()
// let h1 = <h1>{time}</h1>
// // 一个组件最外层的标签只能有一个
// let root = document.getElementById('root')
// 直接写不建议使用

let root = document.getElementById('root')
let bgclass = 'bgRed'
// 在classname中调用则app.css中该变量对应的选择器为 .
let mystyle = {
  borderBottom: '12px solid blue',
  'font-size': '26px'
  /* jsx中定义style第一个单词照常第二个单词首字母大写
  或者该属性用引号引起来*/
  // 不建议使用引号的形式,控制台会警告
}
function Clock(props) {
  // 注意函数式开发函数首字母要大写
  return (
    <h1 className={bgclass} style={mystyle}>
      {props.date.toLocaleTimeString()}
      <div>//注释测试</div>
      {/* jsx中只能这样写注释,
      上面的</div>即使灰了也并没有被注释 */}
    </h1>
    // 其中style中定义样式只能事对象的形式,即{变量}或{{样式}}
  )
}
// ReactDOM.render(<Clock date={new Date()} />, root)
// props用于传值,单向流动只能从父到子
// 函数式组件开发,静态组件

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
下面是类式组件基础
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

class Jsclass extends React.Component {
  constructor(props) {
    super(props)
  }
  // 同样类组件名首字母也要大写
  render() {
    return (
      <div>
        <p>{this.props.num}</p>
        <button onClick={this.props.myclick}>父传子</button>
        <button onClick={() => { console.log(this.props.children); }}>控制台查看插槽</button>
        {this.props.children[0]}
        {/* 插槽通过children */}
        <Clock date={new Date()}></Clock>
      </div>
    )
  }
}
// 类组件开发,动态组件

function myvar(props) {
  // 路由调用的组件
  console.log(props);
  // 输出props,获取路由参数等
  return (<span>{props.location.state.msg}</span>)
  // 用变量渲染
}

function id(props) {
  // 路由调用的组件
  console.log(props);
  // 输出props,获取路由参数等
  return (<span>{props.match.params.path}</span>)
  // 用变量渲染
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
下面是redux的部分,下面将用函数组件实现,redux使用比较麻烦,不知道要不要就不用
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

const reducer = function (state = { num: 0 }, action) {
  switch (action.type) {
    case "add":
      state.num++
      break
    case "sub":
      state.num--
      break
    default:
      break
  }
  return { ...state }
  // 结构赋值,最好要加
}
// 管理redux仓库的对应方法
const store = createStore(reducer)
// 创建仓库,用reducer处理action,结果放入store
function add() {
  store.dispatch({ type: 'add' })
  // 调用store中的dispatch传入action
}
function sub() {
  store.dispatch({ type: 'sub' })
}
function Counter(props) {
  let state = store.getState()
  // store.getState()为获取数据
  return (
    <div>
      <div>这是计数{state.num}</div>
      {/* state下放的redux数据 */}
      <button onClick={add}>加一</button>
      <button onClick={sub}>减一</button>
    </div>
  )
}
store.subscribe(() => {
  ReactDOM.render(<Plusclass />, root)
})
// store.subscribe()订阅仓库数据变化,使用回调重新渲染实现数据动态改变

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
下面是react-redux的部分,不需要订阅监听仓库数据变化,下面将用类组件实现,react-redux使用比较麻烦,不知道要不要就不用
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

class Counterclass extends React.Component {
  render() {
    const value = this.props.value
    // 通过state传给props,直接使用props就可以获取
    const onAddClick = this.props.onAddClick
    console.log(this.props);
    return (
      <div>
        <div>这是计数{value}</div>
        {/* state下放的redux数据 */}
        <button onClick={onAddClick}>加一</button>
      </div>
    )
  }
}
const addAction = {
  type: 'add'
}

function reducer2(state = { value: 0, other:'这是其他值'}, action) {
  // state可以传多个值,但是不要忘了在mapStateToProps中写映射
  switch (action.type) {
    case "add":
      state.value++
      console.log(state.value);
      break
    default:
      break
  }
  // 不限于使用Switch,也可以构建一个函数对action.type判断调用
  return { ...state }
}

const store2 = createStore(reducer2)

function mapStateToProps(state) {
  // 函数名自定义但是最好采用mapStateToProps代表state映射
  return {
    value: state.value,
    other:state.other
    // state中的值不要忘记绑定
  }
}
const mapDispatchToProps = (dispatch) => {
  // 函数名自定义但是最好采用mapDispatchToProps代表dispatch映射
  return {
    onAddClick: () => {
      dispatch(addAction)
    }
    // 这里是映射的方法
    // 方法要绑定才能使用
  }
}

const ReactRedux = connect(mapStateToProps, mapDispatchToProps)(Counterclass)
// connect为react-redux的关联方法,可以将组件外的方法映射的仓库中,形成新的组件

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
下面是总的组件,并结合了路由
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

class Plusclass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      num: 0,
      list: ['列表1', '列表2', '列表3']
    }
    // state管理,这里对类不熟悉还需要加强js学习

    // this.myclick = this.myclick.bind(this)
    // 事件绑定this,这里对this的理解还需要学习
  }

  // myclick() {
  //   this.setState({
  //     num:this.state.num+1
  //   })
  // }
  myclick = (e) => {
    this.setState({
      num: this.state.num + 1
    })
  }
  /* 两种方式,上面那种需要写绑定,
  箭头函数直接就可以用,但是箭头函数会造成额外渲染 */
  // 箭头函数的this就是外部的this,而匿名函数的this是匿名函数本身

  history = () => {
    console.log(this.props);
  }

  render() {
    if (false) {
      return '这是条件渲染的一种方式'
    }
    else {
      return (
        <Provider store={store2}>
          {/* 用react-redux封装的最外层组件Provider,传入store
            与redux不一样,不用订阅渲染
          */}
            <p onClick={this.myclick}>点我改变{this.state.num}</p>
            {/* 在react中原生事件被代理了,想要调用需要采用驼峰命名法,
          其值必须用变量的形式表示 */}
            {/* 函数传参不能直接用 函数(参数) ,
          要使用 (e)=>{函数(参数,e)} 这种回调函数的形式(e可有可无),
          否则会被当成字符串,只在加载时调用一次 */}
            {this.state.num == 1 || this.state.num == 2 ? <h4>此时为1或2</h4> : '这是条件渲染'}
            <Jsclass myclick={this.myclick} num={this.state.num}>
              <h4>插槽1</h4>
              <h3>插槽2</h3>
              {/* 这里是插槽,在组件的this.props.children获取 */}
            </Jsclass>
            {/* 子传父父传子原理都是父传子,子传父只是调用父为子传入的方法 */}

            {this.state.list.map((e, i) => {
              return <div id={i} key={i}>{e}</div>
            })}
            {/* 列表渲染用遍历的方法实现,相对vue复杂一些 */}
            <Router>
              {/* 可以写多个Router */}
              <Link to='/'>显示路由</Link>  
            <Link to='/root' replace>显示路由root不可回退到上一个路由(狂点该路由只能回退一次)</Link>  
            {/* replace 为替换,即替换上一个路由的histroy栈
            即不可回退到上一个路由 */}
              <Link to={{ pathname: "/myvar", search: '?username=admin', hash: "#abc", state: { msg: '我的消息' } }}>这里是变量</Link>  
            {/* 这里采用变量的形式传递路由 */}
              {/* 控制台props含有的history */}
              <Link to='/id/456'>动态渲染路由参数</Link>  
            {/* 控制台props含有的history */}
              {/* history里的方法可以进行路由的存储查找前进后退等 */}
              <Route path='/' exact>路由</Route>
              {/* exact 精确匹配 */}
              <Route path='/root'>路由root</Route>
              <Route path='/myvar' component={myvar}></Route>
              {/* 以component关联的组件渲染 */}path:
            <Route path='/id/:path' component={id}></Route>
              {/* 动态渲染路由参数 */}
            </Router>
            <br />
            <Router basename='/jionMe'>
              {/* basename为基础路径会在加载的路由前面加上该路径 */}
              <Link to='/'>显示路由(两个Route本应该加载两次)</Link>  
            <Link to='/root'>显示路由root</Link>  
            <Link to='/home'>虽然是home但是重定向到root</Link>  
            <Switch>
                {/* Switch使只有第一个Route加载 */}
                <Route path='/' exact>第一个路由</Route
              <Route path='/' exact>第二个路由</Route
            {/* 在 / 路由的属性中加入 exact 可以使其Route值可以被替换,
            exact 意为精确匹配 */}
              </Switch>
              <Route path='/root'>路由root</Route>
              <Route path='/home'>虽然是home但是重定向到root
            <Redirect to='/root'></Redirect>
                {/* 重定向一般配合条件跳转,使用场景不多 */}
              </Route>
            </Router>
            <br />
            <Counter></Counter>
            <br />
            <ReactRedux></ReactRedux>
            <App></App>
            {/* 调用App这个组件 */}
        </Provider>
      )
    }
  }
}


ReactDOM.render(<Plusclass />, root)

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister()

// export default demoCom
// 导出名为demoCom的组件,用在子组件中服务于父组件的调用
生命周期

组件的生命周期可分成三个状态:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

生命周期的方法有:

  • componentWillMount 在渲染前调用,在客户端也在服务端。
  • componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
  • componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
  • shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 可以在你确认不需要更新组件时使用。
  • componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
  • componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
  • componentWillUnmount在组件从 DOM 中移除之前立刻被调用。

鄂ICP备19018246号-1