React02

React02

前端三大框架中, 来自 Facebook 公司提供的 React.

基本理念: 简化原生DOM操作. 函数封装简化 => 自制 JSX 语法简化

  • angular, vue: 在html 书写 JS 代码
  • react : 在 JS 中书写 HTML

组件制作方式

组成页面的零件 – 复用

  • 函数
    • 函数名必须大驼峰
    • 必须继承父类: React.Component
    • 固定的 render() 方法, 返回页面

脚手架

npm i -g  create-react-app

create-react-app 包名

启动: npm start
localhost:3000

事件

onClick={this.方法名}

注释方法中的this指向
普通函数:  使用bind 绑定this   
this.函数.bind(this, 其它参数)

采用箭头函数保障this
()=>  this.方法名(参数)

状态值

state 和 setState

数据变化 会同步影响UI 的数据 都应该存放在state中
setState() 来更新时数据, 同步就会刷新UI

setState() 具有更新UI的特征:  有时也用来调用 实现UI的刷新

样式

style={ {属性名: 值, 属性名:值} }

外部样式css的引入:  必须带 路径标识  ./  /  ../
import './App.css'

className="样式类"

双向数据绑定

  • value: 负责 数据绑定到UI
  • onChange: UI变化 绑定变化值给 数据项
<input value={this.state.xxx}  onChange={event => this.setState({xxx: event.target.value})
// rcc
import React, { Component } from "react";

import "./App.css";

export default class App extends Component {
  // 名称 价格 数量
  // 分析: 数量变化 会导致 UI变化的值 -- 放state中
  state = { count: 5, uname: "", upwd: "", msg: "", msgColor: "" };

  //不会变化的值普通属性即可
  name = "iPhone";
  price = 8999;

  // 特征: 普通函数 && 事件触发 && 其中用this
  // bind 或 箭头函数调用:  保障this指向
  _doMinus() {
    this.setState({ count: this.state.count - 1 });
  }

  // 推荐: 方法最好是 箭头函数 -- 直接规避this指向问题
  _countChanged = (event) => {
    let count = event.target.value;

    // 只有数字才更新给数量
    // ^开头 $结尾 \d数字  * 0个及以上
    if (/^\d*$/.test(count)) {
      this.setState({ count });
    }
  };

  // 事件函数:
  // * 普通函数: 有this指向问题的风险要处理
  // * 箭头函数: 没有this指向问题
  _doLogin = () => {
    //doudou 123456
    if (this.state.uname == "doudou" && this.state.upwd == "123456") {
      this.setState({ msg: "登录成功", msgColor: "green" });
    } else {
      this.setState({ msg: "登录失败", msgColor: "red" });
    }
  };

  render() {
    return (
      <div>
        {/* 作业2 */}
        <div>
          <div>
            <input
              value={this.state.uname}
              onChange={(event) => this.setState({ uname: event.target.value })}
            />
          </div>
          <div>
            <input
              type="password"
              value={this.state.upwd}
              onChange={(event) => this.setState({ upwd: event.target.value })}
            />
          </div>
          <button onClick={this._doLogin}>登录</button>
          <h4 style={{ color: this.state.msgColor }}>{this.state.msg}</h4>
        </div>

        {/* 作业1 */}
        <div className="goods-cell">
          <span>{this.name}</span>
          <span>¥{this.price}</span>
          <div>
            <button
              onClick={() => this._doMinus()}
              disabled={this.state.count == 1}
            >
              -
            </button>
            <button
              onClick={this._doMinus.bind(this)}
              disabled={this.state.count == 1}
            >
              -
            </button>
            <input
              value={this.state.count}
              style={{ width: "25px", textAlign: "center" }}
              onChange={this._countChanged}
            />
            <button
              onClick={() => this.setState({ count: this.state.count + 1 })}
            >
              +
            </button>
          </div>
          <span>¥{this.state.count * this.price}</span>
        </div>
      </div>
    );
  }
}

.goods-cell {
  width: 400px;
  display: flex;
  justify-content: space-evenly;
  border-radius: 3px;
  border: 1px solid purple;
  margin: 10px auto;
  padding: 5px;
}

条件渲染

vue中: v-if

angular: *ngIf

// 条件渲染: if
// rcc
import React, { Component } from "react";

export default class App extends Component {
  state = { score: 60 };

  // 条件渲染: 依赖原生的if判断 -- 制作函数 根据不同条件返回不同的 JSX

  // 非事件触发: 不涉及this指向问题
  showRes() {
    // setState(): 会刷新所有 数据变更时 相关 的UI
    let score = this.state.score;

    if (score < 60) {
      return <p>很遗憾, 您的成绩不及格!</p>;
    } else if (score >= 60 && score < 90) {
      return <b>您的成绩良好!</b>;
    } else {
      return <h2>恭喜您, 成绩优秀!</h2>;
    }
  }

  showRank() {
    let score = this.state.score;

    if (score < 20) {
      return <p>黑铁</p>;
    } else if (score < 40) {
      return <p>青铜</p>;
    } else if (score < 60) {
      return <p>白银</p>;
    } else if (score < 80) {
      return <p>黄金</p>;
    } else {
      return <p>铂金</p>;
    }
  }

  render() {
    return (
      <div>
        {/* {}中的代码 在页面渲染时 会自动触发! */}
        {this.showRes()}
        <h3>您的分数是:{this.state.score} </h3>
        <button onClick={() => this.setState({ score: this.state.score - 10 })}>
          减分
        </button>
        <button onClick={() => this.setState({ score: this.state.score + 10 })}>
          加分
        </button>

        {this.showRank()}
      </div>
    );
  }
}

练习

// 条件渲染: 根据某个值 来决定显示什么UI

import React, { Component } from "react";

export default class App extends Component {
  state = { isLogin: false, uname: "" }; // isLogin 自制属性, 存储登录状态

  // 条件渲染 依赖函数
  show() {
    if (this.state.isLogin) {
      return (
        <div>
          <span>
            欢迎, <b>{this.state.uname}</b>
          </span>
          <button onClick={() => this.setState({ isLogin: false })}>
            退出
          </button>
        </div>
      );
    } else {
      return (
        <div>
          <input
            type="text"
            value={this.state.uname}
            onChange={(event) => this.setState({ uname: event.target.value })}
          />
          <button onClick={() => this.setState({ isLogin: true })}>登录</button>
        </div>
      );
    }
  }

  render() {
    return <div>{this.show()}</div>;
  }
}

列表渲染

vue中: v-for

angular: *ngFor

// 列表渲染  for
import React, { Component } from "react";

export default class App extends Component {
  emps = [
    { name: "凯凯", age: 29, gender: 1 },
    { name: "蒙蒙", age: 19, gender: 0 },
    { name: "涛涛", age: 25, gender: 1 },
    { name: "小月", age: 16, gender: 0 },
    { name: "欣哥", age: 42, gender: 1 },
  ];

  names = ["亮亮", "东东", "然然", "小新", "华哥"];

  names_btns = [
    <button>亮亮</button>,
    <button>东东</button>,
    <button>然然</button>,
    <button>小新</button>,
    <button>华哥</button>,
  ];

  // 自动化处理: 使用for循环遍历数组, 每一项放到 jsx 语法中, 形成新的数组
  showBtns() {
    let arr = [];

    this.names.forEach((item, index) => {
      // react要求: 列表中的每一项必须有唯一标识key
      let btn = <button key={index}>{item}</button>;
      arr.push(btn);
    });

    return arr;
  }

  showLis() {
    //1.空数组
    let arr = [];
    //2.遍历每一项, 改造成JSX 然后添加到数组中
    this.names.forEach((item, index) => {
      arr.push(<li key={index}>{item}</li>);
    });
    //3.返回含有JSX的数组
    return arr;
  }

  showTrs() {
    let arr = [];

    this.emps.forEach((item, index) => {
      // react中不存在 过滤器 和 管道的说法  {{ xxx | pipe }}
      // 为什么要有管道/过滤器:  vue/angular 在html中写js不方便

      // react就是JS  不存在写JS不方便的情况
      let sex = ["女", "男"][item.gender]; // 数组[序号]

      arr.push(
        <tr key={index}>
          <td>{index + 1}</td>
          <td>{item.name}</td>
          <td>{item.age}</td>
          <td>{sex}</td>
        </tr>
      );
    });

    return arr;
  }

  render() {
    return (
      <div>
        {/* 数组的默认处理: 自动把数组每一项形式到页面上 */}
        <div>{this.names}</div>
        {/* <div>{this.names_btns}</div> */}
        <div>{this.showBtns()}</div>
        <ul>{this.showLis()}</ul>

        <table border="1">
          {/* DOM对 结构要求严格,  tr应该出现在 tbody thead 或 tfoot 里 */}
          <thead>
            <tr>
              <td>序号</td>
              <td>姓名</td>
              <td>年龄</td>
              <td>性别</td>
            </tr>
          </thead>
          <tbody>{this.showTrs()}</tbody>
        </table>
      </div>
    );
  }
}

map函数简化 列表渲染

// map方法 简化 列表渲染

import React, { Component } from "react";

export default class App extends Component {
  names = ["lucy", "lily", "john", "mike"];

  // 语法糖: ()=> { return xxxx; }   简化为 () => xxx
  showBtns = () =>
    this.names.map((item, index) => <button key={index}>{item}</button>);

  showLis = () => this.names.map((item, index) => <li key={index}>{item}</li>);

  // showBtns() {
  //   return this.names.map((item, index) => {
  //     return <button key={index}>{item}</button>;
  //   });
  //   // return arr;
  // }

  render() {
    return (
      <div>
        {this.showBtns()}
        <ul>{this.showLis()}</ul>
      </div>
    );
  }
}

生命周期

不同的组件, 从出生 到 销毁 之间经历的过程: 生命周期

过程中的关键节点 都会触发对应的函数 — 钩子函数

// 生命周期

//rcc
import React, { Component } from "react";

export default class App extends Component {
  state = { show: false, age: 10 };

  render() {
    return (
      <div>
        <button onClick={() => this.setState({ show: !this.state.show })}>
          切换Son组件的显示
        </button>
        {this.state.show ? <Son age={this.state.age} /> : ""}
        <button onClick={() => this.setState({ age: this.state.age * 2 })}>
          增加age: {this.state.age}
        </button>
      </div>
    );
  }
}

//子组件
class Son extends Component {
  state = { num: 1 };

  componentDidMount() {
    // 挂载时:  同vue的 mounted
    console.log("componentDidMount: 组件显示时, 挂载");
  }

  // 面试问题: 如何提高 React 渲染效率
  // 此生命周期的返回值 将会决定页面要不要刷新
  shouldComponentUpdate(props, state) {
    // 传入的值: 即将变成什么样, 问: 要不要刷新UI
    console.log("shouldComponentUpdate:", state);

    // num为偶数不更新
    if (state.num % 2 == 0) {
      console.log("num是偶数, 不刷新UI");
      return false;
    } //false代表不更新UI

    console.log("num是奇数, 刷新UI");
    return true;
  }

  // props: 父子传参的值, 类似于vue 的 props 属性
  // <Son name="东东" />  则 props = {name:'东东'}
  componentDidUpdate(old_props, old_state) {
    // 数据发生更新
    // 参数都是发生更新之前的值
    console.log("componentDidUpdate: 更新前", old_props, old_state);
    console.log("componentDidUpdate: 更新后", this.props, this.state);
  }

  componentWillUnmount() {
    //将要卸载时: 同vue的 destroy
    console.log("componentWillUnmount: 组件将要消失时, 卸载");
  }

  render() {
    return (
      <div>
        <h3>我是Son组件</h3>
        <button onClick={() => this.setState({ num: this.state.num + 1 })}>
          {this.state.num}
        </button>
      </div>
    );
  }
}

网络请求

然哥: ajax

东哥: axios

华哥: 小程序 wx.request

小新: angular的网络服务 this.http.get().subscribe()

React 本身不具备网络请求模块, 此处与vue相同, 使用 axios

到项目下, 执行 aixos 安装命令

npm i axios

日期处理库 moment

http://momentjs.cn/

安装

npm i moment
// 练习

import React, { Component } from "react";

import axios from "axios";
// 引入 JS 日期处理模块:  需要安装 npm i moment
import moment from "moment";

import "./App.css";

export default class App extends Component {
  state = { data: null };

  componentDidMount() {
    this.getNews(1);
  }

  getNews(pno) {
    let url =
      "http://101.96.128.94:9999/mfresh/data/news_select.php?pageNum=" + pno;

    axios.get(url).then((res) => {
      console.log(res);

      this.setState({ data: res.data });
    });
  }

  showNews = () =>
    this.state.data.data.map((item, index) => {
      // 箭头函数的语法糖不支持复杂方法体.  只能改为非语法糖写法
      // 时间戳 -> 年-月-日
      // moment(日期类型).format(格式化的样子)
      // pubTime:是字符串类型, 需要转数字类型才能给 Date() 使用

      // http://momentjs.cn/docs/#/displaying/format/
      let date = moment(new Date(item.pubTime * 1)).format("YYYY-MM-DD");

      return (
        <div key={index} className="news-cell">
          <span>{item.title}</span>
          <span>{date}</span>
        </div>
      );
    });

  showPages() {
    // 语法糖, 快速解包
    let { pageCount, pageNum } = this.state.data;
    // let pageCount = this.state.data.pageCount
    // let pageNum = this.state.data.pageNum

    let arr = [];

    // 极限值
    if (pageNum == 1) {
      arr.push(
        <span key="prev" className="disabled">
          上一页
        </span>
      );
    } else {
      arr.push(
        <span key="prev" onClick={this.getNews.bind(this, pageNum - 1)}>
          上一页
        </span>
      );
    }

    for (let i = 1; i <= pageCount; i++) {
      arr.push(
        <span
          key={i}
          className={pageNum == i ? "cur" : ""}
          onClick={() => this.getNews(i)}
        >
          {i}
        </span>
      );
    }

    // 极限值
    if (pageNum < pageCount) {
      arr.push(
        <span key="next" onClick={this.getNews.bind(this, pageNum + 1)}>
          下一页
        </span>
      );
    } else {
      arr.push(
        <span key="next" className="disabled">
          下一页
        </span>
      );
    }

    return arr;
  }

  render() {
    if (!this.state.data) return <div></div>;

    return (
      <div className="news">
        <div className="content">{this.showNews()}</div>
        <div className="pages">{this.showPages()}</div>
      </div>
    );
  }
}

.goods-cell {
  width: 400px;
  display: flex;
  justify-content: space-evenly;
  border-radius: 3px;
  border: 1px solid purple;
  margin: 10px auto;
  padding: 5px;
}

.news {
  width: 700px;
  margin: 0 auto;
}

.news-cell {
  display: flex;
  justify-content: space-between;
  border-bottom: 1px dashed gray;
  padding: 8px;
}

.pages {
  text-align: center;
  margin-top: 10px;
  user-select: none;
}

.pages > span {
  padding: 2px 8px;
  display: inline-block;
  border-radius: 4px;
  border: 1px solid gray;
  color: gray;
  margin: 0 2px;
}

.pages > span:not(.disabled):hover,
.pages > .cur {
  background-color: orange;
  color: white;
  border-color: orange;
}

.pages > .disabled {
  color: lightgray;
  border-color: lightgray;
}

ReactNative

提前说:

  • 有Android手机同学, 最好带数据线 — 要真机调试
  • 没有Android 手机 , 有模拟器 比较卡.
  • 有 iPhone同学, 必须搭配 苹果Mac 电脑使用!
    • 要想发布软件 给别人用 还要交700元 给Apple
  • windows电脑
    • 明天带着搭建编译环境, 保证可用!
  • mac电脑
    • 靠自强! https://reactnative.cn/docs/getting-started.html
.pages > span:not(.disabled):hover,
.pages > .cur {
  background-color: orange;
  color: white;
  border-color: orange;
}

.pages > .disabled {
  color: lightgray;
  border-color: lightgray;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值