React框架基础学习

  • 前言
  • 1 第一章
  • 1.1 认识React
  • 1.2 React元素渲染
  • 1.3 React_JSX
  • 1.4 React样式和注释
  • 1.5React组件
  • 1.6React State
  • 第二章
  • 2.1 React父传子数据传递
  • 2.2 React子传父数据传递
  • 2.3 React事件处理
  • 2.4 React条件渲染
  • 2.5React列表渲染
  • 2.6 React组件API
  • 第三章
  • 3.1 组件生命周期
  • 3.2 表单和图表
  • 第四章
  • 4.1 React插槽
  • 4.2 React路由react-router
  • 4.3 react-redux


前言

前端React框架学习,以此篇博客记录所学,如有误载,感谢您的指正。
视频教程地址:https://www.bilibili.com/video/BV1T7411W72T?p=1

1 第一章

1.1 认识React

功能和特性:
React功能:构建用户界面的JavaScript库,主要用于构建UI界面。特性:

  • 声明式的设计。
  • 高效,采用虚拟DOM来实现DOM的渲染,最大限度的减少DOM的操作。
  • 灵活,跟其他库灵活搭配使用。
  • JSX,俗称JS里面写HTML,JavaScript语法的扩展。
  • 组件化,模块化,代码易复用。
  • 单向数据流,没有实现数据的双向绑定,数据->视图->事件->数据。

创建第一个项目:
1、通过script引入使用,仅用于学习调试使用:

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

2、进入工作目录,打开控制台终端,通过react的脚手架,创建项目进行开发,部署。

npm install -g create-react-app
create-react-app <项目名称>

注:npm为nodejs的包管理命令。 Windows安装nodejs和换源教程链接:

1.2 React元素渲染

JSX创建JS元素对象:

let h1 = <h1>helloworld</h1>;

注:JSX元素对象,或者组件对象,必须只有1个根元素(根节点)Demo:

function clock(){
    let time = new Date().toLocaleTimeString()
    let element = (
        <div>
            <h1>现在的时间是{time} </h1>
            <h2>这是副标题</h2>
        </div>
    )
    let root = document.querySelector('#root');
    ReactDOM.render(element,root)
}
clock()
setInterval(clock,1000)

函数式组件渲染:

function Clock(props){
    return (
                <div>
                    <h1>现在的时间是{props.date.toLocaleTimeString()} </h1>
                    <h2>这是函数式组件开发</h2>
                </div>
    )
}
function run(){
    ReactDOM.render(
        <Clock date={new Date()} />,
        document.querySelector('#root')
    )
}
setInterval(run,1000)

1.3 React_JSX

表达式:

  • 由HTML元素构成
  • 中间如果需要插入变量用{}
  • {}中间可以使用表达式
  • {}中间表达式中可以使用JSX对象
  • 属性和html内容一样都是用{}来插入内容
    注意:1、JSX必须要有根节点。2、正常的普通HTML元素要小写。如果是大写,默认认为是组件。 Demo:
import React from 'react';
import ReactDOM from 'react-dom';
import './App.css'

let time = new Date().toLocaleTimeString()
let str = '当前时间是:'
let element = (
    <div>
        <h1>helloworld</h1>
        <h2>{str+time}</h2>
    </div>
)
console.log(element)
let man = '发热';
let element2 = (
    <div>
        <h1>今天是否隔离</h1>
        <h2>{man=="发热"?<button>隔离</button>:"躺床上"}</h2>
    </div>
)
//let man = '发热';
let element4 = (
    <div>
        <span>横着躺</span>
        <span>竖着躺</span>
    </div>
)
man = '正常'
let element3 = (
    <div>
        <h1>今天是否隔离</h1>
        <h2>{man=="发热"?<button>隔离</button>:element4}</h2>
    </div>
)
let color = 'bgRed'
let logo = 'https://www.baidu.com/img/pc_1c6e30772d5e4103103bd460913332f9.png'
//HTML的样式类名要写className,因为class在js当中是关键词
let element5 = (
    <div className={color}>
        <img src={logo} />
        红色的背景颜色
    </div>
)
ReactDOM.render(
    element5,
    document.getElementById('root')
)

1.4 React样式和注释

1、Class,style中,不可以存在多个class属性,错误的表示如下:

<div class=’abc’  class={‘active’}>

2、style样式中,如果存在多个单词的属性组合,第二个单词开始,首字母大写。或者用引号引起来,否则会报错。

let exampleStyle = {
    background:"skyblue",
    borderBottom:"4px solid red",
    'background-image':"url(https://www.baidu.com/img/pc_1c6e30772d5e4103103bd460913332f9.png)"
}

3、多个类共存的操作

let element2 = (
    <div>
        <h1 className={"abc "+classStr}>helloworld</h1>
    </div>
)
let classStr2 = ['abc2','redBg2'].join(" ")
let element3 = (
    <div>
        {/* 这里写注释 */}
        <h1 className={classStr2} style={exampleStyle}>helloworld</h1>
    </div>
)

4、注释
必须在括号的表达式{/* 这里写注释 */}内书写,否则报错。

1.5React组件

函数式组件与一般用于静态没有交互事件内容的组件页面,类组件一般会有交互或者数据修改的操作,复合式组件两者均包含。

函数式组件Demo:

function Childcom(props){
    console.log(props)
    let title = <h2>我是副标题</h2>
    let weather = props.weather
    //条件判断 
    let isGo = weather=='下雨' ?"不出门":"出门"
    return (
        <div>
            <h1>函数式组件helloworld</h1>
            {title}
            <div>
                是否出门?
                <span>{isGo}</span>
            </div>
        </div>
    )
}

类组件Demo:

class HelloWorld extends React.Component{
    render(){
        console.log(this)
        return (
            <div>
                <h1>类组件定义HELLOWORLD</h1>
                <h1>hello:{this.props.name}</h1>
                <Childcom weather={this.props.weather} />
            </div>
        )
    }
}

复合组件Demo:

import React from 'react';
import ReactDOM from 'react-dom';
import './04style.css';
//函数式组件
function (props){
    console.log(props)
    let title = <h2>我是副标题</h2>
    let weather = props.weather
    //条件判断 
    let isGo = weather=='下雨' ?"不出门":"出门"
    return (
        <div>
            <h1>函数式组件helloworld</h1>
            {title}
            <div>
                是否出门?
                <span>{isGo}</span>
            </div>
        </div>
    )
}
//类组件定义
class HelloWorld extends React.Component{
    render(){
        console.log(this)
//返回的都是JSX对象
        return (
            <div>
                <h1>类组件定义HELLOWORLD</h1>
                <h1>hello:{this.props.name}</h1>
                <Childcom weather={this.props.weather} />
            </div>
        )
    }
}
ReactDOM.render(
    <HelloWorld name="老陈" weather="下雨" />,
    document.querySelector('#root')
)

1.6React State

React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
Demo:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

第二章

2.1 React父传子数据传递

React使用props父传子:
props传递给子组件数据,单向流动,可以是任意的类型,不能直接子传递给父。但props可以传递父元素的函数,就可以去修改父元素的state,从而达到传递数据给父元素。Props可以设置默认值

HelloMessage.defaultProps = {  name:”老陈”,msg:“helloworld”  }

Demo:

//在父元素中使用state去控制子元素props的从而达到父元素数据传递给子元素
class ParentCom extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isActive:true
        }
        this.changeShow = this.changeShow.bind(this)
    }
    render(){
        return (
            <div>
                <button onClick={this.changeShow}>控制子元素显示</button>
                <ChildCom isActive={this.state.isActive} />
            </div>
        )
    }
    changeShow(){
        this.setState({
            isActive:!this.state.isActive
        })
    }
}

class ChildCom extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        let strClass = null;
        // if(this.props.isActive){
        //     strClass = ' active'
        // }else{
        //     strClass = ""
        // }
        strClass = this.props.isActive?" active":"";

        return (
            <div className={"content"+strClass}>
                <h1>我是子元素</h1>
            </div>
        )
    }
}

ReactDOM.render(
    <ParentCom />,
    document.querySelector("#root")
)

props和state的区别:
区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。

2.2 React子传父数据传递

调用父元素的函数从而操作父元素的数据,从而实现数据从子元素传递至父元素
Demo:

import React from 'react';
import ReactDOM from 'react-dom';

//子传父
class ParentCom extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            childData:null
        }
    }
    render(){
       return (
           <div>
                <h1>子元素传递给父元素的数据:{this.state.childData}</h1>
               <ChildCom setChildData={this.setChildData} />
           </div>
       ) 
    }
    setChildData=(data)=>{
        this.setState({
            childData:data
        })
    }
}
class ChildCom extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            msg:"helloworld"
        }
    }
    render(){
        return (
            <div>
                <button onClick={this.sendData}>传递helloworld给父元素</button>
                <button onClick={()=>{this.props.setChildData('直接调用props的函数')}}>传递helloworld给父元素</button>
            
            </div>
        )
    }
    sendData=()=>{
        //console.log(this.state.msg)
        //将子元素传递给到父元素,实际就是调用父元素传递进来的父元素函数
        this.props.setChildData(this.state.msg)
    }
}
ReactDOM.render(
    <ParentCom />,
    document.querySelector('#root')
)

2.3 React事件处理

语法:
1、React 事件绑定属性的命名采用驼峰式写法,而不是小写。
2、如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)

无参Demo:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    // 这边绑定是必要的,这样 `this` 才能在回调函数中使用
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }
  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}
ReactDOM.render(
  <Toggle />,
  document.getElementById('example')
);

事件传参:

{/* 使用ES6箭头函数传递多个参数 */}
<button  onClick={(e)=>{this.parentEvent1('msg:helloworld',e)}}>提交</button>
{/* //不使用ES6箭头函数传递多个参数的方式 */}
<button  onClick={function(e){this.parentEvent1('不使用es6,msg:helloworld',e)}.bind(this)}>提交</button>

事件对象:React返回的事件对象是代理的原生的事件对象,如果想要查看事件对象的具体值,必须直接输出事件对象的属性。
注意: 原生阻止默认行为时,可以直接返回return false;React中,阻止默认必须e.preventDefault();

2.4 React条件渲染

React中条件渲染和JavaScript中的一致,条件运算,如if…else…三元运算符等。
条件运算Demo:

import React from 'react';
import ReactDOM from 'react-dom';

function UserGreet(props){
    return (<h1>欢迎登陆</h1>)
}
function UserLogin(props){
    return (<h1>请先登录</h1>)
}
class ParentCom extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isLogin:true
        }
    }
    render(){
        if(this.state.isLogin){
            return (<UserGreet></UserGreet>)
        }else{
            return (<UserLogin></UserLogin>)
        }
    }
}
ReactDOM.render(
    <ParentCom></ParentCom>,
    document.querySelector('#root')
)

三目运算Demo:

import React from 'react';
import ReactDOM from 'react-dom';

function UserGreet(props){
    return (<h1>欢迎登陆</h1>)
}
function UserLogin(props){
    return (<h1>请先登录</h1>)
}

class ParentCom extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            isLogin:false
        }
    }
    render(){
        let element = null;
        if(this.state.isLogin){
            element = <UserGreet></UserGreet>;
        }else{
            element = (<UserLogin></UserLogin>);
        }
        return (
            <div>
                <h1>这是头部</h1>
                {element}
                <h1>这是三元运算符的操作</h1>
                {this.state.isLogin?<UserGreet></UserGreet>:<UserLogin></UserLogin>}
                <h1>这是尾部</h1>
            </div>
        )
    }
}

ReactDOM.render(
    <ParentCom></ParentCom>,
    document.querySelector('#root')
)

2.5React列表渲染

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

Demo:

function ListItem(props) {
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('example')
);

2.6 React组件API

  • 设置状态:setState
  • 替换状态:replaceState
  • 设置属性:setProps
  • 替换属性:replaceProps
  • 强制更新:forceUpdate
  • 获取DOM节点:findDOMNode
  • 判断组件挂载状态:isMounted

第三章

3.1 组件生命周期

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

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

生命周期的方法有:

  • compontWillMount:组件将要渲染,AJAX,添加动画前的类
  • compontDidMount:组件渲染完毕,添加动画
  • compontWillReceiveProps:组件将要接受props数据,查看接收props的数据什么
  • shouldComponentUpdate:组件接收到新的state或者props,判断是否更新。返回布尔值
  • compontWillUpdate:组件将要更新
  • componentDidUpdate:组件已经更新
  • componentwillUnmount:组件将要卸载
    这些方法的详细说明,可以参考官方文档https://reactjs.org/docs/react-component.html#lifecycle-methods

3.2 表单和图表

HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素生来就保留一些内部状态。在 HTML 当中,像 <input>, <textarea>, 和<select>这类表单元素会维持自身状态,并根据用户输入进行更新。但在React中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。

Demo在子组件上使用表单:

/** onChange 方法将触发 state 的更新并将更新的值传递到子组件的输入框的 value 上来重新渲染界面。
需要在父组件通过创建事件句柄 (handleChange) ,并作为 prop (updateStateProp) 传递到你的子组件上。
*/

class Content extends React.Component {
  render() {
    return  <div>
            <input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} /> 
            <h4>{this.props.myDataProp}</h4>
            </div>;
  }
}
class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: 'Hello Runoob!'};
      this.handleChange = this.handleChange.bind(this);
  }
 
  handleChange(event) {
    this.setState({value: event.target.value});
  }
  render() {
    var value = this.state.value;
    return <div>
            <Content myDataProp = {value} 
              updateStateProp = {this.handleChange}></Content>
           </div>;
  }
}
ReactDOM.render(
  <HelloMessage />,
  document.getElementById('example')
);

Demo多个表单的使用:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };
 
    this.handleInputChange = this.handleInputChange.bind(this);
  }
 
  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
 
    this.setState({
      [name]: value
    });
  }
 
  render() {
    return (
      <form>
        <label>
          是否离开:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          访客数:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

第四章

4.1 React插槽

组件中写入内容,这些内容可以被识别和控制。React需要自己开发支持插槽功能。
原理:
从props中获取组件中写入的HTML。
Demo:
组件中根据HTML内容的不同,插入的位置不同。

import React from 'react';
import ReactDOM from 'react-dom';

class ParentCom extends React.Component{
    render(){
        console.log(this.props)
        return (
            <div>
                <h1>组件插槽</h1>
                {this.props.children}
                <ChildCom>
                    <h1 data-position="header">这是放置到头部的内容</h1>
                    <h1 data-position="main">这是放置到主要的内容</h1>
                    <h1 data-position="footer">这是放置到尾部的内容</h1>
                </ChildCom>
            </div>
        )
    }
}

class ChildCom extends React.Component{
    render(){
        let headerCom,mainCom,footerCom;
        this.props.children.forEach((item,index)=>{
           if(item.props['data-position']==='header'){
            headerCom = item
           }else if(item.props['data-position']==='main'){
               mainCom = item
           }else{
               footerCom = item
           }
        })
        return (
            <div>
                <div className="header">
                    {headerCom}
                </div>
                <div className="main">
                    {mainCom}
                </div>
                <div className="footer">
                    {footerCom}
                </div>
            </div>
        )
    }
}

class RootCom extends React.Component{
    constructor(props){
        super(props)
        //console.log(props)
        this.state = {
            arr:[1,2,3]
        }
    }
    render(){
        return (
            <ParentCom>
                <h2 data-name="a" data-index={this.state.arr[0]}>子组件1</h2>
                <h2 data-name="b" data-index={this.state.arr[1]}>子组件2</h2>
                <h2 data-name="c" data-index={this.state.arr[2]}>子组件3</h2>
            </ParentCom>
        )
    }
}

ReactDOM.render(
    <RootCom></RootCom>
    ,
    document.querySelector("#root")
)

4.2 React路由react-router

官方文档:https://reactrouter.com/web/guides/quick-start安装:

npm install react-router-dom --save

react-router四大组件:
Router:所有路由组件的根组件(底层组件),包裹路由规则的最外层容器。
属性:basename->设置此路由根路径,router可以在1个组件中写多个。
Route:路由规则匹配组件,显示当前规则对应的组件。
Link:路由跳转的组件。
Switch:让switch组件内容的route只匹配1个,只要匹配到了,剩余的路由规则将不再匹配。
Demo:

import React from 'react';
//hash模式
//import {HashRouter as Router,Link,Route} from 'react-router-dom'
//history模式/后端匹配使用
import {BrowserRouter as Router,Link,Route} from 'react-router-dom'

function Home(){
    return (
        <div>
            <h1>admini首页</h1>
        </div>
    )
}

function Me(props){
    console.log(props)
    return (
        <div>
            <h1>admin个人中心</h1>
        </div>
    )
}

function Product(){
    return (
        <div>
            <h1>admin产品页面</h1>
        </div>
    )
}

function News(props){
    console.log(props)
    return (
        <div>
            新闻页,新闻id:{props.match.params.id}
        </div>
    )
}

class App extends React.Component{
    
    render(){
        let meObj = {
            pathname:"/me",//跳转的路径
            search:"?username=admin",//get请求参数
            hash:"#abc",//设置的HASH值
            state:{msg:'helloworld'}//传入组件的数据
        };
        return (
            <div id="app">
          
                <Router>
                    <div className="nav">
                        <Link to="/">Home</Link>
                        <Link to="/product">Product</Link>
                        <Link to={ meObj }   replace>个人中心</Link>
                        <Link to="/news/4568789">新闻页</Link>
                    </div>
                    <Route path="/" exact component={Home}></Route>
                    <Route path="/product" component={Product}></Route>
                    <Route path="/me" exact component={Me}></Route>
                    <Route path="/news/:id" component={News}></Route>
                </Router>
            </div>
        )
    }
}

export default App

重定向组件:
如果访问某个组件时,如果有重定向组件,那么就会修改页面路径,使得页面内容显示为所定向路径的内容。
Demo:

function LoginInfo(props){
    //props.loginState = 'success';
    //props.loginState = "fail"
    console.log(props)
    if(props.location.state.loginState === 'success'){
        return <Redirect to="/admin"></Redirect>
    }else{
        return <Redirect to="/login"></Redirect>
    }
}

4.3 react-redux

react-redux是state管理工具:
中文官方API文档:http://cn.redux.js.org/docs/react-redux/api.html#api