react入个门
阅读原文时间:2023年07月09日阅读:2

react 特点

  • 不使用模板
  • 不是一个mvc框架
  • 响应式
  • 轻量级的js库

原理

  • 虚拟dom 将dom抽象成js对象
  • diff算法

搭建开发环境

react.js 核心文件

react-dom.js 面向web端 渲染页面的dom 依赖于react核心文件

react-native 面向移动端app

babel.js 将es6 转换成es5 jsx转化成javascript

脚手架

npm install -g create-react-app
create-react-app -version 查看版本
create-react-app [projectName]  //构建项目
npm start //启动

jsx语法

  • js+xml的组合

    ReactDOM.render(

    hello world

    , document.getElementById("root"));
    // document.getElementById("root")获取插入的容器
    // jsx语法

    hello world

    遇到 <> 按照xml语法解析,遇到{} 按照js 语法解析

元素的渲染

function tick() {
    const element = (  //括号--->需要显示多行标签时使用括号
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {new Date().toLocaleTimeString()}.</h2>
      </div>
    );
    ReactDOM.render(element, document.getElementById('root'));
  }

  setInterval(tick, 1000);

组件

//新建文件封装
import React from "react";
class App extends React.Component {
 render() {
   return ( //多行标签用()
     <div>
       <h1> Hello, world!!!!!!! </h1>
       <h2> It is {new Date().toLocaleTimeString()}. </h2>
     </div>
   );
 }
}

export default App;


 import App from './App'
 ReactDOM.render(<App />, document.getElementById("root"));

props

 //父组件中传入 des字段
 ReactDOM.render(<App des="这是react框架" />, document.getElementById("root"));


//子组件中通过 this.props[字段名]获取数据
class App extends React.Component {
  render() {
    return (
      <div>
        <h1> Hello, world!!!!!!! {this.props.des}</h1>
        <h2> It is {new Date().toLocaleTimeString()}. </h2>
      </div>
    );
  }
}

state

constructor(props) {
    super(props);
    this.state = {  //构造函数中定义state
      count: 10,
    };
  }

  render() {
    return (
      <div>
        <h1> Hello, world!!!!!!! {this.props.des}</h1>
        <h2> It is {this.state.count}. </h2>  //使用state中的变量
      </div>
    );
  }

生命周期

)

  • componentWillMount:在组件渲染之前使用(beforeMount)
    conponentDidMount:渲染完成(mounted)
    componentUnMount:销毁组件 (beforeDestory)清除定时器等

    import React from "react";
    class App extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
    count: 10,
    };
    }
    componentWillMount() {
    console.log("componentWillMount");
    }
    componentDidMount() {
    console.log("componentDidMount");
    }
    componentWillUnmount() {
    console.log("componentWillUnmount");
    }
    shouldComponentUpdate() {
    return true;
    }
    componentWillUpdate() {
    console.log("componentWillUpdate");
    }
    componentDidUpdate() {
    console.log("componentDidUpdate");
    }
    // componentWillReceiveProps() {
    // console.log("componentWillReceiveProps");
    // }
    addCount = () => {
    console.log(this.state)
    //this.state.count += 1;
    this.setState({
    count: (this.state.count += 1),
    });
    };
    render() {
    return (

    Hello, world!!!!!!! {this.props.des}

    It is {this.state.count}.


    );
    }
    }

    export default App;

  • 由上图可知:

    • 单纯渲染组件时 componentWillMount--->componentDidMount

    • 改变state时:shouldComponentUpdate(返回true允许改变,否则不继续运行)---> componentWillUpdate--->componentDidUpdate

    • 由于props是单向传递,当父组件改变props时,触发子组件componentWillReceiveProps函数,

      componentWillReceiveProps-->shouldComponentUpdate(返回true允许改变,否则不继续运行)---> componentWillUpdate--->componentDidUpdate

  • 注:this.state.count += 1;这种直接改变state不会去刷新组件,自然也不会触发生命周期函数,使用setState函数改变state才会重新渲染组件

数据的子传父与父传子

父传子
//父组件
import App from "./App.jsx";
ReactDOM.render(<App des="这是react框架" />, document.getElementById("root"));  //组件中自定义属性
//子组件
//构造器
  constructor(props) {
    super(props);  //super接受props对象
    this.state = {
      count: 10,
    };
  }
  //
    render() {
    return (
      <div>
        <h1> Hello, world!!!!!!! {this.props.des}</h1> 通过this.props调用对应的属性
        <h2> It is {this.state.count}. </h2>
        <button onClick={this.addCount}>增加</button>
      </div>
    );
  }
子传父
  • (利用事件的回传,类似vue中的$emit自定义事件)

    //父组件中
    //构造器中定义变量
    constructor() {
    super();
    this.state={
    title:'123'
    }
    }
    //定义所要触发的事件
    changeCount = (data) => {
    this.setState({
    title: data,
    });
    };
    //组件中传递props

子组件可以看到父组件传递的props:

)

//子组件中
    //定义事件
    addCount = () => {
           this.props.clickChange('子组件传递来的参数');//形参传递给父组件,父组件接收后改变state,然后回传给子组件,子组件重新渲染
      };
      //渲染
  render() {
    return (
      <div>
        <h1> Hello, world!!!!!!! {this.props.title}</h1>
        <button onClick={this.addCount}>增加</button> //传入子组件中定义的事件,然后再触发该事件里面父组件自定义的clickChange事件
      </div>
    );
  }

条件渲染

  //构造器state中定义isLogin变量
  this.state = {
      count: 10,
      isLogin: false,
    };
   //渲染的时候
  changeLogin = () => {
    this.setState({
      isLogin: true,
    });
  };
   render() {
    const { isLogin } = this.state;
    let login = isLogin ? <div>已登陆</div> : <div>未登陆</div>;
    return (
      <div>
        {login} //
        <button onClick={this.changeLogin}>改变登陆状态</button>
      </div>
    );
  }

列表渲染

//state中定义一个数组对象
   userInfo: [
        {
          name: "张三",
          age: 12,
        },
        {
          name: "李四",
          age: 13,
        },
        {
          name: "王五",
          age: 14,
        },
      ],

 //render中遍历数组对象进行渲染
    render() {
    return (
      <div>
        <ul>
          {this.state.userInfo.map((el,index) => {
            return (
              <li key={index}>  //注意在最外层添加key,否则会产生警告
                <span>{el.name}</span>
                <span>{el.age}</span>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }

)

ref

//构造器中创建ref
 constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
//访问ref  通过current属性获取dom对象
this.myRef.current.style.color="red"

受控组件与非受控组件

受控组件
//state动定义
   this.state = {
      value: "",
      value2: "",
      value3: "",
    };
//改变时通过e.target获取值
changeVaue = (e) => {
    this.setState({
      value: e.target.value,
    });
  };
  changeVaue2 = (e) => {
    this.setState({
      value2: e.target.value,
    });
  };
  changeVaue3 = (e) => {
    this.setState({
      value3: e.target.value,
    });
  };
//对input的值进行更新
      <input
          type="text"
          value={this.state.value}
          onChange={this.changeVaue}
        />
        <input
          type="text"
          value={this.state.value2}
          onChange={this.changeVaue2}
        />
        <input
          type="text"
          value={this.state.value3}
          onChange={this.changeVaue3}
        />
非受控组件
  • 当表单的重复工作太多,数据变化的每种方式都编写事件处理函数,比如上面受控组件的情况,这个时候用非受控组件可以很好的解决

    //构造器中创建变量,和ref来操作dom
    this.state = {
    value1: "",
    value2: "",
    value3: "",
    };
    this.myValue1 = React.createRef();
    this.myValue2 = React.createRef();
    this.myValue3 = React.createRef();
    //将值与ref节点一一对应



    //提交时获取state的值
    this.myValue1.current.value //

状态提升

  • 通过一个父组件来管理多个子组件中的数据

    //父组件
    import React from "react";
    import MyComponent from "./component";
    import MyForm from "./form";
    import Child1 from "./component/child1";
    import Child2 from "./component/child2";

    class App extends React.Component {
    constructor() {
    super();
    this.state = {
    money: 8,

    };

    }
    handleChange = (e) => {
    this.setState({
    money: e.target.value,
    });
    };
    render() {
    return (

    ¥: $:

    );
    }
    }
    export default App;

    //自组件
    import React from "react";
    export default class Child1 extends React.Component {
    constructor() {
    super();

    }

    render() {
    return (

    {this.props.money }


    );
    }
    }

组件的组合

  • 类似vue的slot插槽

    //父组件
    组件的组合

    //子组件 通过this.props.children调用

    {this.props.children}

PropsTypes类型检查(poprs)

import React from "react";
import PropTypes from "prop-types";
export default class Child1 extends React.Component {
  constructor() {
    super();
  }

  render() {
    return <p>{this.props.money}</p>;
  }
}

//定义传入props的参数类型
Child1.PropTypes = {
  money:PropTypes.number,  //number类型
  sex:PropTypes.string.isRequired, //string类型,必选
};
// 指定 props 的默认值:
Child1.defaultProps = {
  name: 'Stranger'
};

安装

npm install react-router-dom --save

基础

//两个子路由
//Mine.jsx
import React from "react";
export default class Mine extends React.Component {
  render() {
    return <div>Mine</div>;
  }
}
//Home.jsx
import React from "react";
export default class Home extends React.Component {
  render() {
   return  <div>Home</div>;
  }
}


//App.jsx
import Home from "./pages/Home";
import Mine from "./pages/Mine";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class App extends React.Component {
    render() {
        return (
          <div>
            <Router>
              <Route path="/home" component={Home}></Route>
              <Route path="/mine" component={Mine}></Route>
            </Router>
          </div>
        );
  }
}

两种路由类型

  • 哈希类型(HashRouter) 锚点链接

  • History(BrowserRouter)h5新特性 history.push()来实现

    import { BrowserRouter as Router } from "react-router-dom"; //使用history模式
    x import { HashRouter as Router } from "react-router-dom"; //使用hash模式

路由的跳转

import { HashRouter as Router, Route, Link } from "react-router-dom";//引入Link组件
//使用
<Router>
    <ul>
        <li>
            <Link to="/home">Home页面</Link> //导航地址
        </li>
        <li>
            <Link to="/mine">Mine页面</Link>
        </li>
    </ul>
    <Route path="/home" component={Home}></Route>
    <Route path="/mine" component={Mine}></Route>
</Router>

路由的匹配问题

exact:bool
  • 现在有两个路径 /person/man/person,

  • 默认情况下 跳转到/person/man时,也会匹配到person

    //解决方法   使用exact来实现精准匹配
     <Route exact={true} path="/person" component={人类}></Route>
     <Route  path="/person/man" component={男人}></Route>
strict:bool
  • 更为严格的匹配方式,将地址末尾有 /与无 / 的情况当作两个地址