React 基础学习

98 阅读6分钟

基本语法

reactjs语法进行了扩展,发明了jsx语法,通过babel转换成js语法而被浏览器认识。 想要使用jsx一定要先引入react

    //引入react
    import { Component } from 'react';
    import { render } from 'react-dom';
    import './Student.css'
    //这里以class组件为例子
    class Student extends Component{
        constructer(props){
            super(props)
            //组件的状态
            this.state = {
                age:16,
                class:'lisi',
                isShow:false
            }
        }
        //通过入口函数render来返回jsx
        render(){
        
            return  (
                {/*可以进行条件判断if..else.. 、三元运算符等*/}
                let showSubmitBtn = null
                if(this.state.isShow){
                    showSubmitBtn = (<button>点击</button>)
                }else{
                   showSubmitBtn =(<span>...</span>)
                 }
                <div>
                    
                    {/*点击事件onClick 所有的变量都要用{}包裹起来*/}
                    <div onClick={changeAge}>{this.state.age}</div>
                    {/*这里的传递参数:data-   样式名:className*/}
                    <div data-name="lizi" onClick={changeName} className='AgeCalss'>
                        {this.state.name}
                    </div>
                    {showSubmitBtn}
                </div>
            )
        }
        changeAge = () =>{
            //修改数据使用setState
            this.setState({
                age:18
            })
        }
        changeName = (e) =>{
           //jsx上传递过来的数据
           //console.log(e.target.dataset.name)
           this.setState({
               name:e.target.dataset.name
           })
        }
    }
//渲染到root
render(
    <Student />,
    document.getElementById('root)
)

{}里面可以是基本数据类型String、Number...,也可以使dom节点(<button>按钮</button>),还可以是声明的节点变量let el = (<button>按钮</button>)

react事件

  1. 事件名驼命名
  2. 必须有个{} 传入一个函数
<button onClick={()=>{this.props.changeFun(this.state.curtitle)}}>点击向父元素传递数据</button>

事件对象:react 返回的事件对象是代理的原生的事件对象,如果想要查看事件对象的具体值,必须之间输出事件对象的属性

原生:阻止默认行为,可以直接返回return false

react 中阻止默认行为,e.preventDefault()

react 事件中传参:

如果需要获取事件对象就像下面这样使用,如果不需要获取事件对象就直接this.preventEvent

    <button onClick={(e)=>this.preventEvent('msg',e)}></button>

列表渲染

将列表内容拼装成数组,放置到模板中,将数据拼装成数组的jsx对象,使用数组的map方法 对每一项数据按照jsx的形式进行加工,最终得到一个每一项都是jsx对象的数组,再将数组渲染到模板中

这里要注意key值放置到每一项中否侧会报错(组件的话放在组件上)

class Father extends Component{
  constructor(props){
    super(props)
    this.state = {
      users:[
        {name:'lisi',age:'25'},
        {name:'zhangsan',age:'26'},
        {name:'wangwu',age:'27'},
      ]
    }
  }
  render(){
    return(
      <div>
        {this.state.users.map((item,index)=>{
          return (<p key={index}>{item.name}:{item.age}</p>)
        })}
      </div>
    )
  }
}

生命周期

生命周期:组件从实例化到渲染到最终从页面销毁

整个过程就是生命周期,在生命周期中有许多可以调用的事件,俗称钩子函数

3个状态

  • Mounting:将组件插入到DOM中
  • Updating:将数据更新到dom中
  • Unmounting: 将组件移除到dom中

生命周期中的钩子函数(方法、事件)

  • ComponentWillMount:组件将要渲染 ajax,添加动画前的类
  • ComponentDidMount:组件渲染完毕 添加动画
  • ComponentWillReceiveProps:组件将要接收props数据 查看接收props的数据是
  • ShouldComponentUpdate:组件接收到新的state或者props判断是否更新,返回布尔值
  • ComponentWillUpdate:组件将要更新
  • ComponentDidUpdate:组件已经更新
  • ComponentWillUnmount: 组件将要卸载
class Lifecom extends Component{
    constructor(props){
        super(props)  //调用继承Component的构造函数
        this.state ={msg:'123'}
    }
    componentWillUnmount(){
        console.log('组件将要渲染');
    }
    componentDidMount(){
        console.log('组件渲染完毕');
    }
    componentWillReceiveProps(props){
        console.log('组件将要接收props数据:'+props.Pmsg);
        this.setState({
            msg:props.Pmsg
        })
    }
    shouldComponentUpdate(){
        console.log('组件接收到新的state或者props判断是否更新,返回布尔值')
        return true
    }
    componentWillUpdate(){
        console.log('组件将要更新');
    }
    componentDidUpdate(){
        console.log('组件已经更新');
    }
    componentWillUnmount(){
        console.log('组件将要卸载');
    }
    render(){
        return (
            <div>{this.props.Pmsg}</div>
        )
    }
 }

组件

无状态组件

即函数式组件

     //clothes.js
     //函数式组件返回dom
     function clothes(props){
         return (<div>black shirt</div>)
     }
     export default clothes;

类组件

import { Component } from 'react';
//组件继承Component
class Index extends Component {
    render() {
        return (
            <div>
                
            </div>
        );
    }
}

export default index;

组件间通信

父传子

通过props传递参数

    //Father
    import { Component } from 'react';
    class Father extends Component {
        render() {
            return (
                <div>
                   <Son name='传递数据' /> 
                </div>
            );
        }
    }
    //Son.js
    const Son = (props) =>{
        return (<div>{props.name}</div>)
    }

子传父

    //Father
    import { Component } from 'react';
    class Father extends Component {
        render() {
            return (
                <div>
                   <Son fatherback={this.fatherback} /> 
                </div>
            );
        }
        fatherback = (msg) =>{
            console.log(msg)
        }
    }
    //Son.js
    const Son = (props) =>{
        return (<div onClick={()=>props.fatherback('子组件数据')}>点击之后向父组件传递参数</div>)
    }

全局状态管理redux

解决react 数据管理,用户大中型项目,数据比较庞大时候组件之间数据交互多的情况下使用, 若果你不知道是否需要redux那么你就不需要用他。

  • 解决组件的数据通信
  • 解决数据和交互较多的应用

redux只是一种状态管理的解决方案

  • store:数据仓库,保存数据的地方
  • state:是一个对象,数据仓库里面的数据都放到一个state里面
  • action: 一个动作,触发数据改变的方法
  • reducer:是一个函数,通过获取动作改变数据,生成一个新的state,从而改变页面

在使用之前可以先安装调试工具:redux devtools

    npm install redux react-redux --save

index.js

//provider包裹在根组件外层,使所有的子组件都可以拿到state
import { Provider } from "react-redux";
import { render } from 'react-dom';
// 创建仓库
import store from "./store";
// 业务逻辑
import Myapp from "./Myapp";
const app = (
    <Provider store={store}>
        <Myapp />
    </Provider>
)

render(
    app,
    document.getElementById('root')
)

store.js

import { createStore } from "redux";
//初始化数据,处理数据的地方
import reducer from "./component/reducer";
//创建仓库
const store = createStore(
    reducer,
    //加上这句话为了唤起调试工具redux devtools
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()    
)

export default store;

reducer.js

const defaultState = {
    inoutval:0,
    list:[
        {id:1,title:'看不懂操作'}
    ]
}
const fun = (state=defaultState,action) => {
    console.log(action);
    //判断action.type 来处理数据
    switch (action.type) {
        case "add_val":
            state.inoutval++
            break;
        case "dec_val":
            state.inoutval--
            break;
        default:
            break;
    }
    //防止数据前后数据相同不进行触发
    return {...state}
}
export default fun;

Myapp.js

import React, { Component } from 'react';
//把 React 组件和 Redux 的 store 真正连接起来
import { connect } from "react-redux";

class Myapp extends Component {
    constructor(props){
        super(props)
    }
    render() {
        return (
            <div>
                //所有redux管理的数据通过props获取
                <p>这里展示数据:{this.props.inoutval}</p>
                <button onClick={this.props.changeClick}>改变数据</button>
            </div>
        );
    }
}
//这个函数允许我们将`store`中的数据作为`props`绑定到组件上
const mapStateToProps = ((state)=>{
    return {
        //获取state上的数据
        inoutval:state.inoutval
    } 
})
//action`作为`props`绑定到`Myapp`上
const mapDispatchToProps = ((dispatch)=>{
    return {
        changeClick(){
            //定义调用type为* 的方法的参数
            const action = {
                type:'add_val',
                value:1
            }
            dispatch(action)
        }
    }
})

export default connect(mapStateToProps, mapDispatchToProps)(Myapp)

想要详细了解connect的同学可以看看这位大兄弟的文章

react 插槽

与vue直接提供一个slot不同,react的插槽功能需要自己来实现

//父组件
class Father extends Component {
    render() {
        return (
            <Child>
                {/* 我们想要在子组件展示这些内容 */}
                <h1 data-index="1">这是H1</h1>
                <h2 data-index="2">这是H2</h2>
                <h3 data-index="3">这是H3</h3>
                <h4 data-index="4">这是H4</h4>
            </Child>
        )
    }
}
//子组件
class Child extends Component {
    constructor(props){
        super(props)
    }
    render() {
        let H1,H2,H3,H4;
        console.log(this.props.children);
        this.props.children.forEach(item=>{
            if(item.props['data-index']==='1'){
                H1 = item
            }else
            if(item.props['data-index']==='2'){
                H2 = item
            }else
            if(item.props['data-index']==='3'){
                H3 = item
            }else
            if(item.props['data-index']==='4'){
                H4 = item
            }
        })
        return (
            <div>
                <div>在这里展示插槽</div>
                <span>H1</span>
                {H1}
                <span>H2</span>
                {H2}
                <span>H3</span>
                {H3}
                <span>H4</span>
                {H4}
            </div>
        )
    }
}

react 路由

npm install react-router-dom --save
//index.js
import { BrowserRouter as Router, Link, Route, Routes } from 'react-router-dom';
import List from "./component/list.js";
import Detail from "./component/detail.js";
class RouterDom extends Component {
    render() {
        let pathObj = {pathname:'/user',search:'?username=admin',hash:'#abc',state:{msg:'helloworld'}}
        // console.log(User);
        return (
            <div>
                <Router>
                    <Routes>
                        <Route path='/user' element={<div>user</div>}></Route>
                    </Routes>
                </Router>
                {/**
                 * basename:设置路由的根路径
                 *  */}
                <Router basename='/admin'>
                    <div>
                        <Link to='/'>index</Link>
                        <Link to='/home'>home</Link>
                        <Link to={ pathObj }>user</Link>
                        <Link to='list'>list</Link>
                    </div>
                    {/**
                     * 所有的路由要包含在routes节点中
                      */}
                    <Routes>
                    {/**exact 精确匹配
                     * 
                    */}
                    {/** 
                     * element 属性用来展示我们当前第值展示的组件内容
                     * 
                     */}
                        <Route path='/' exact element={<h1>INDEX</h1>}></Route>
                        <Route path='/home' exact element={<h2>HOME</h2>}></Route>
                        <Route path='/list' exact element={ <List /> }></Route>
                        <Route path='/list/:id' exact element={ <Detail /> }></Route>
                    </Routes>
                </Router>
            </div>
        )
    }
}
// list.js
import React from 'react';
import { Link, useNavigate } from "react-router-dom";

function List() {
    let list = [
        { name: 'lisi', id: 1 },
        { name: 'zhangsan', id: 2 }
    ]
    //自定义跳转
    const to = useNavigate()
    return (
        <div>
            {list.map(item => {
                return (
                    <Link key={item.id} to={'/list/' + item.id}>{item.name}</Link>
                )
            })}
            <hr />
            {list.map(item => {
                return (
                    <button key={item.id} onClick={() => {
                        to('/list/' + item.id, { state: item })
                    }}>{item.name}</button>
                )
            })}
        </div>
    );

}
//detail.js
import React from 'react';
//获取路径参数
import { useParams, useLocation } from "react-router-dom";

function Detail() {
    const params = useParams();
    const userlocation = useLocation()
    console.log(params);
    console.log(userlocation);
    return (
        <div>
            <div>
                详情
                params:
                {params.id}
                <hr />
                location:
                {userlocation.state.name}
            </div>
        </div>
    );
}

以上就是整里的react基础知识点,当然现在react主推Hooks,不过class组件官方表示没有干掉的意思,更期待组合使用。