react基础

环境准备

node安装

项目的运行和启动必须依赖于环境,以前jquery时代只用在网页上写js脚本,现在要搭环境配置复杂,但代码简洁。

node.js是一个基于Chrome V8引擎的js运行环境。

作用:
1.前端开发环境
Webpack:编写插件辅助启动前端项目,
Npm插件:
Server:

2.服务端动态编程语言(后台,接口,动态脚本供前端调用,数据库对接)
Java Web:
PHP Web:
Node Web:

Npm使用(包管理工具)

官网:https://npmjs.com

语法使用:
npm -v
npm init
npm install | npm install -g

插件发布:
npm adduser | npm pulish
npm config set registry https://registry.npmjs.org/
npm config set registry https://registry.npm.taobao.org/
npm unpublish [包名] --force

Yarn使用

特点:速度快、更安全、更可靠
(一般vue,react脚手架都有内置yarn)

官网:https://yarn.bootcss.com/
安装:npm install yarn -g
更新:npm upgrade yarn -g
npm upgrade yarn@1.13.0 -g

语法使用:
yarn -v
yarn init
yarn install
yarn add/remove
yarn publish/login/logout
yarn run

React框架

React介绍

特点:

  • 声明式
  • 组件化(ui)
    模块化:功能划分
  • 灵活(单/多页面、服务端渲染、RN-App)

定义组件,渲染组件,获取标签

编写HelloWorld

引入框架:
1.CDN(多页面开发)
https://unpkg.com/react@16/umd/react.development.js
https://unpkg.com/react-dom@16/umd/react-dom.development.js
https://unpkg.com/babel-standalone@6/babel.min.js
(生产环境中不建议使用)

2.NPM

src>npm install react --save
package.json

react-demo>npm i

基本用法:
渲染标签:ReactDOM.render()
创建标签:React.createElement()
创建组件:React.Component
(es6,用extends继承组件)

es5,npm:(不建议)

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>React demo</title>
  <script src="../node_modules/react/umd/react.development.js"></script>
  <script src="../node_modules/react-dom/umd/react-dom.development.js"></script>
</head>
<body>
  <div id="app"></div>
  <script>
    var hello = React.createElement('h1',{},"Hello World");
    ReactDOM.render(hello,document.getElementById('app'));
  </script>
</body>
</html>

es6,label:(使用较多)

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>React demo</title>
  <script src="../node_modules/react/umd/react.development.js"></script>
  <script src="../node_modules/react-dom/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id="app"></div>
  <script type="text/babel">
    // 组件渲染,
    ReactDOM.render(
      <h1>Hello,World!</h1>  
    ,document.getElementById('app'));
  </script>
</body>
</html>

JSX语法介绍

JSX介绍:
1.原始

<script type="text/babel">
  // 创建元素标签,并添加class,name属性
    var hello = React.createElement(
      'h1',{
        className:'red',
        name:'jack'
      },"Hello World!");
    // 渲染标签
    ReactDOM.render(
      hello
    ,document.getElementById('app'));
  </script>

2.JSX(类名class为避免混淆,使用className,red可用于设置样式)

<script type="text/babel">
    // 渲染标签
    ReactDOM.render(
      <h1 className="red" name="jackk">Hello,World!!</h1>
    ,document.getElementById('app'));
  </script>

3.穿插使用
先定义标签变量,然后传入Dom树中,变量用{}

 <style>
    .red {
      color: red;
    }
  </style>

<script type="text/babel">
    var name = 'jack';
    var ele =  <h1 className="red" name="jackk">Hello,{name}!!</h1>
    // 渲染标签,元素渲染到根 DOM 节点中
    ReactDOM.render(
     ele
    ,document.getElementById('app'));
  </script>

元素渲染

1.如何渲染:单向绑定
(模型变化会驱动视图改变,视图发生变化同样会反映到模型中
元素发生变化如何更新:只更新对应节点(diff算法)
定时器例子;
在 setInterval() 回调函数,每秒都调用 ReactDOM.render()来更新(自更新需要更新的部分)

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>React demo</title>
  <script src="../node_modules/react/umd/react.development.js"></script>
  <script src="../node_modules/react-dom/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <style>
    .red {
      color: red;
    }
  </style>
</head>
<body>
  <div id="app"></div>
  <script type="text/babel">
    function tick(){
      var time = new Date().toLocaleTimeString();
      var ele =  <div>
        <h1 className="red" name="jackk">Hello,Jack!!</h1>
        <h2>今天是:{time}</h2>
      </div>
      ReactDOM.render(
      ele
      ,document.getElementById('app'));
    }
    
    setInterval(tick,1000);
  </script>
</body>
</html>

组件和props介绍(重点)

组件抽取(头,尾,面包屑)
基本语法:
1.React.createClass()
2.函数式组件(无状态组件,return一个常规标签)

<script type="text/babel">
    // 函数式组件
    function Hello(props){
      return <div>
        <h1>Hello,{props.name}!!</h1>
        <p>年龄:{props.age}</p>
        <p>擅长:js</p>
      </div>
    }
    const ele = <Hello name="jack" age="30"/>;
    ReactDOM.render(
      ele,
      document.getElementById('app'));
  </script>

执行流程:
1)我们调用 ReactDOM.render() 函数,并传入 <Hello name="jack" age="30"/> 作为参数。
2)React 调用 Hello组件,并将 {name: “jack” ,age: “30”} 作为 props 传入。
3)Hello组件将 <h1>Hello, jack</h1> 元素作为返回值。
4)React DOM 将 DOM 高效地更新为 <h1>Hello, jack</h1>

3.React.Component(有状态用this取值,生命周期要用render来渲染组件,继承实现)

<script type="text/babel">
    // class继承
    class HelloJack extends React.Component{
      render(){
        return <div>
          <h1>Hello,{this.props.name}!!</h1>
          <p>年龄:{this.props.age}</p>
          <p>擅长:js</p>
        </div>
      }
    }
    ReactDOM.render(
      <HelloJack name="jackk" age="22"/>
      ,document.getElementById('app'));
  </script>

函数式组件 vs Class组件

函数式组件:
接受唯一参数props,并返回一个react元素对象
Class组件:(有状态)
继承实现、有this、有生命周期(用render来渲染)

组合组件

在一个大容器中多次渲染子组件

function App() {
        return (
          <div>
            <Hello name="Sara" />
            <Hello name="Cahal" />
            <Hello name="Edite" />
          </div>
        );
    }
    // 渲染组件
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    );

当组件内部有嵌套关系,导致难以复用时,需要拆分提取组件

React生命周期(逻辑处理)

组件状态:state
state 是私有的,并且完全受控于当前组件
修改 State:不要直接修改,要用this.setState()

state异步更新?

// 错误
this.setState({
  counter: this.state.counter + this.props.increment,
});

让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:

// Correct
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

State 的更新会被合并?

constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

当state有多个变量时,分别条用setState()来单独更新

  componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

浅合并,this.setState({comments}) 完整保留了 this.state.posts, 但是完全替换了 this.state.comments

组件之间如何传值:(单向数据流)

组件的 state只能向下流动
父组件可以选择把它的 state 作为 props 向下传递到它的子组件中:

<FormattedDate date={this.state.date} />
function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

子组件接收的props,无法知道它是来自于 Clock 的 state,或是 Clock 的 props,还是手动输入的

四个阶段:

1.组件初始化阶段(Initialization)

2.组件加载阶段(Mounting)
componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行

3.数据更新阶段(Updation)

4.组件销毁阶段(Unmounting)

<script type="text/babel">
    class Hello extends React.Component{
        constructor(props) {
          console.log('初始化阶段')
          // 初始化props
          super(props);
          // 初始化状态
          this.state = {
            name: 'kack',
            age: 32
          }
        }
        
        // 组件加载前,一般在这个阶段发起ajax请求来渲染界面
        componentWillMount(){
          console.log('组件加载前');
        }
        // 组件加载后
        componentDidMount() {
          console.log('组件加载后')
        }
        // 要用箭头函数,原来的this指向button对象,现在指向当前的react实例
        updateUser = () => {
          // 错误语法,并不能更新数据
          // this.state.name = 'Tim';
          this.setState({
            name: 'Tim',
            age: 22
          })
        }

        // 数据更新,组件状态发生变化
        shouldComponentUpdate(){
          console.log('数据是否需要更新')
          return true;
          // 会执行更新
        }
        componentWillUpdate(){
          console.log('数据将要更新')
        }
        componentDidUpdate(){
          console.log('数据已经更新')
        }

        // 组件状态发生变化:组件加载或数据更新
        render() {
          console.log('组件加载或数据更新')
          return <div>
            <h1>Hello,{this.state.name}!!</h1>
            <p>年龄:{this.state.age}</p>
            <p>擅长:js</p>
            <button onClick={this.updateUser}>更新数据</button>
          </div>
        }
      }

    ReactDOM.render(
      <Hello />
      ,document.getElementById('app'));
  </script>

执行顺序:初始化、组件加载前、组件加载、组件加载后
constructor(props)、componentWillMount()、render()、componentDidMount()
组件更新:是否需要更新、数据将要更新、数据更新、数据更新完
shouldComponentUpdate()、componentWillUpdate()、render()、componentDidUpdate()

事件处理(事件绑定)

<button onClick={this.updateUser}>更新数据</button>

绑定的事件要用箭头函数,如果直接使用函数要手动再绑定this,class 的方法默认不会绑定 this

<script type="text/babel">
    class Hello extends React.Component{
        constructor(props) {
          console.log('初始化阶段')
          // 初始化props
          super(props);
          // 初始化状态
          this.state = {
            name: 'kack',
            age: 32
          }
          // // 2.或手动绑定this
          // this.updateUser = this.updateUser.bind(this);
        }

        // 1.要用箭头函数,原来的this指向button对象,现在指向当前的react实例
        updateUser = () => {
          console.log(this); //指向Hello组件
          // this.setState({
          //   name: 'Tim',
          //   age: 22
          // })
        }

        // 如果直接使用函数,要手动绑定this
        updateUser() {
          console.log(this); //undefined
        }

        // 组件状态发生变化:组件加载或数据更新
        // yuab:<button onClick={this.updateUser}>更新数据</button>
        // 3.<button onClick={() => this.updateUser()}>更新数据</button>
        // 每次渲染 LoggingButton 时都会创建不同的回调函数
        // 4.<button onClick={this.updateUser.bind(this)}>更新数据</button>
        render() {
          console.log('组件加载或数据更新')
          return <div>
            <h1 className="red">Hello,{this.state.name}!!</h1>
            <p>年龄:{this.state.age}</p>
            <p>擅长:js</p>
            <button onClick={this.updateUser}>更新数据</button>
          </div>
        }
      }

    ReactDOM.render(
      <Hello />
      ,document.getElementById('app'));
  </script>

条件渲染

父组件根据this.state.isLogin来判断渲染哪个子组件

<script type="text/babel">
    function Login(props){
      return <button onClick={props.updateUser}>Login</button>
    }
    function Logout(props){
      return <button onClick={props.updateUser}>Logout</button>
    }
    class App extends React.Component{
        // 初始化状态
        state = {
          isLogin: false
        }

        // 1.要用箭头函数,原来的this指向button对象,现在指向当前的react实例
        updateUser = () => {
          console.log(this); //指向App组件
          this.setState({
            // isLogin: true
            isLogin: !this.state.isLogin
          })
        }

        // 组件状态发生变化:组件加载或数据更新
        render() {
          // 获取状态
          // const isLogin =this.state.isLogin;
          const {isLogin} =this.state;
          let button;
          // // 判断
          // if(isLogin) {
          //   button = <Login />
          // }else {
          //   button = <Logout />
          // }
          // {button}
          return <div>
            <h1 className="red">Hello,{this.state.name}!!</h1>
            {isLogin ? <Login updateUser={this.updateUser}/> : <Logout updateUser={this.updateUser}/>}
            <button onClick={this.updateUser}>更新数据</button>
          </div>
        }
      }

    ReactDOM.render(
      <App />
      ,document.getElementById('app'));
  </script>

列表渲染

循环渲染两种方式:数组的map方法、for循环

<script type="text/babel">
    class List extends React.Component{
        // 初始化状态
        state = {
          // list: [1,2,3,4,5]
          list: [
            {id:1, text:'java'},
            {id:2, text: 'js'},
            {id:3, text: 'react'},
            {id:4, text: 'node'},
            {id:5, text: 'php'}
          ]
        }

        // 组件加载或数据更新
        render() {
          const arr = this.state.list;
          const listItem = []
          // 列表循环
          // arr.map((item)=>{
          //   let li = <li>{item}</li>;
          //   listItem.push(li);
          // })
          for(var i=0;i<arr.length;i++){
            let li = <li key={arr[i].id}>{arr[i].text}</li>;
            listItem.push(li);
          }
          return <div>
            <ul>
              {listItem}
            </ul>
          </div>
        }
      }

    ReactDOM.render(
      <List />
      ,document.getElementById('app'));
  </script>

动态列表添加:TodoList实例
注意:在渲染组件时,要绑定key(利用diff算法重新渲染组件时,不会乱序)

<script type="text/babel">
    class TodoList extends React.Component{
        // 初始化状态
        state = {
          val: '',
          list: []
        }
        handleInput = (event)=>{
          this.setState({
            val: event.target.value
          })
        }

        handleAdd = ()=>{
          // const val = this.state.val;
          // const list = this.state.list;
          // es6简写
          const {val, list} = this.state;
          list.push(val);
          this.setState({
            list
          })
        }
        // 组件加载或数据更新
        render() {
          const val = this.state.val;
          const arr = this.state.list;
          const listItem = []
          // 列表循环
          arr.map((item, index)=>{
            let li = <li key={index}>{item}</li>;
            listItem.push(li);
          })
          return <div>
            <div>
              <input type="text" value={val} onChange={this.handleInput} />
              <button onClick={this.handleAdd}>添加</button>
            </div>
            <ul>
              {listItem}
            </ul>
          </div>
        }
      }

    ReactDOM.render(
      <TodoList />
      ,document.getElementById('app'));
  </script>

表单

用js函数可以很方便的处理表单的提交, 同时还可以访问用户填写的表单数据。实现这种效果的标准方式是使用“受控组件”

受控组件

HTML中,表单元素通常自己维护 state,并根据用户输入进行更新
React中,状态的改变通常保存在组件的state中,而且只能通过setState()来更新。
state中初始化 value值,设置值为this.state.value,使得 React 的 state 成为唯一数据源,后续根据handlechange()更新

<script type="text/babel">
    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {value: ''};
    
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
    
      handleChange(event) {
        this.setState({value: event.target.value});
      }
    
      handleSubmit(event) {
        alert('提交的名字: ' + this.state.value);
        event.preventDefault();
      }
    
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              名字:
              <input type="text" value={this.state.value} onChange={this.handleChange} />
            </label>
            <input type="submit" value="提交" />
          </form>
        );
      }
    }
    ReactDOM.render(
      <NameForm />
      ,document.getElementById('app'));
  </script>

textarea 标签

<textarea value={this.state.value} onChange={this.handleChange} />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值