React入门学习(一)

本文介绍了React的基础知识,包括使用create-react-app创建项目、React元素渲染、JSX语法、组件化开发、状态管理和事件处理。通过实例展示了如何创建函数式组件、设置样式、父子组件间的数据传递以及处理用户事件。同时,文章还涵盖了React的条件渲染和列表渲染等核心概念。
摘要由CSDN通过智能技术生成


React是一个构建用户界面的JavaScript库。

React 的特点:

  1. 声明式设计
  2. 高效,采用虚拟DOM来实现dom渲染,减少DOM操作
  3. 灵活, 可以与其他库搭配使用。
  4. JSX,在js中编写html。
  5. 组件化、模块化,代码容易复用
  6. 单向数据流,没有实现数据的双向绑定。数据->视图->时间->数据

create-react-app 创建项目:

通过react脚手架,创建项目来开发部署。

  1. 安装脚手架Create React App yarn global add create-react-app
  2. 创建项目:create-react-app projName
  3. 目录文件解析
    在这里插入图片描述
  4. 启动npm run start或者yarn start

React 元素渲染

  1. 定义一个元素
    注意:元素是一个组件的最小单位。一个元素或组件有且只有一个根节点。这一点和vue是一样的。
    使用JSX写法,可以创建JS元素对象。
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
// 定义一个元素,元素是一个组件的 最小单位。
// 注意:一个元素或者组件有且只有一个根节点。这一点和VUE是一样的。
let h1 = <h1>hello world</h1>
// root.render(h1);
// <App /> JS普通对象
root.render(<App />);

案例1:

function clock() {
  const root = ReactDOM.createRoot(document.getElementById('root'));

  let time = new Date().toLocaleTimeString()
  let ele = (<div>
                <h1>NOW TIME IS : {time}</h1>
              </div>)
  root.render(ele) 
}
setInterval(() => {
  clock()
}, 1000);

案例2:函数式组件

// React 函数式组件
function Clock(props){
  return(<div>
          <h1>NOW TIME IS : {props.date.toLocaleTimeString()}</h1>
          <h2>这是函数式组件开发</h2>
        </div>)
}

function run(){
  root.render(<Clock date={new Date()}/>)
}

setInterval(() => {
  run()
}, 1000);

JSX语法

对html进行扩充。
优点:执行更快,在编译为JS时进行优化(采用虚拟DOM)。类型更安全,在编译时发现错误。编写模板更简单快速。
注意:JSX组件必须要有一个根节点。正常的普通html元素要小写,如果是大写,则默认为组件。

JSX表达式

  1. 由html元素构成
  2. 中间可以使用{}来插入变量
  3. {}中间可以写表达式
  4. {}表达式中可以使用jsx对象
  5. 属性和html内容都是用{}插入

案例:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './App.css'

const root = ReactDOM.createRoot(document.getElementById('root'));

let color = 'bgRed'
// 三元运算
// HTML的类名要些className。因为class是js的关键字
let content2 = (
  <h1>1&gt;2嘛? {1>2?'是':<a className={color} href='#'></a>}</h1>
)

// 字符串拼接 与 模板引入
let time = new Date().toLocaleDateString();
let str = '日期:'
let content = (<div>
  <h1>HUATHY HELLO</h1> 
  <h1>{str + time}</h1>
  {content2}
</div>)

root.render(content)

React样式和注释

JSX_style样式

  1. class、style中,不可以存在多个class属性
  2. style样式中,如果多个单词属性足额,第二个单词首字母大写。或者以引号包裹样式名。

注释

{/* */}:{/* 在元素中的注释必须以大括号包裹起来 */}
//:js注释
/** */:类注释
/* */:多行注释

案例:

  1. index.js
    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './App.css'
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    
    let egstyle = {
      // 样式
      'background-color': 'skyblue',
      borderBottom: '6px solid red'
    }
    // js注释
    let cls = ['greenBorder','high-100'].join(' ');
    let ele = (<div>
      {/* style里面必须是对象,不可以是字符串 */}
      <h1 className={cls} style={egstyle}>HELLO WORLD</h1>
    </div>)
    
    root.render(ele);
    
  2. App.css
    .greenBorder{
      border: 6px solid greenyellow;
    }
    
    .high-100{
      height: 100px;
    }
    

React组件

  1. 函数式组件:静态页面
  2. 类组件(动态组件),一般会有交互和数据修改操作。
  3. 复合组件:组件中包含其他组件(包括类组件和函数式组件)。

区别:类组件中操作事件更方便。函数组件中编写事件方法不太推荐。如果组件中有事件,建议使用类组件。静态组件可以使用函数式组件。

示例:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './App.css'

const root = ReactDOM.createRoot(document.getElementById('root'));

// 函数式组件
function Childcom(props){
  let title = '标题'
  // 条件判断
  let isBig = props.num > 0 ? '是':'否'
  return(<div>
    <h1>HELLO 函数式组件</h1>
    <h2>{title}</h2>
    {/* 大于小于符号可以使用{''}包裹,也可以使用实体符号 */}
    <h2> {props.num} {'>'} 0 ? {isBig}</h2>
  </div>)
}

// 类组件
class Hello extends React.Component{
  render(){
    return(<div>
      <h1>HELLO 类组件定义</h1>
      {/* react组件可以包含组件 */}
      <Childcom num={this.props.num}/>
    </div>)
  }
}

// root.render(<Childcom num='-2' />)
root.render(<Hello num='2'/>)

react状态(React State)

相当于vue中的data。但是和vue不同。

案例一:当前时间

import React from 'react';
import ReactDOM from 'react-dom/client';
import './App.css'

const root = ReactDOM.createRoot(document.getElementById('root'));
/**
 * 类注释
 */
class Hello extends React.Component{
  // 构造函数
  constructor(props){
    // 调用父类方法,会一直传递到继承的类
    super(props)
    // 状态(数据) -- > view
    // 1. 构造函数初始化数据,将需要改变的数据初始化到state中
    this.state = {
      time: new Date().toLocaleTimeString()
    }  
    // 构造函数没有刷新
    console.log(this.state.time)
  }

  render(){
    console.log('这是渲染函数');
    // // 要想时间动起来,可以在这里更改
    // this.state.time = new Date().toLocaleTimeString()
    return(<div>
      <h1>当前时间:{this.state.time}</h1>
    </div>)
  }

  // 生命周期函数,组件渲染完成时
  componentDidMount(){
    setInterval(()=>{
      // 不推荐的改变值方式
      // this.state.time = new Date().toLocaleTimeString()
      /*
        2. 修改state数据。采用this.setState({})的方式会重新渲染内容
        不要直接this.state.dateName=XXX。这种方式不会重新渲染内容。
      */ 
      console.log(this.state.time)
      this.setState({
        time: new Date().toLocaleTimeString()
      })
      /* 这里打印的时间和调用this.setState前是一样的,并没有立即修改dom内容。
        原因:由于很多地方都会修改state,react会对虚拟DOM和DOM之间进行比较。
        当该函数所有设置状态都的修改完成之后,统一对比虚拟dom对象,然后统一修改,提升性能。
      */
      console.log(this.state.time)
    },1000)
  }
}

// // 这种写法不推荐,因为定时函数与渲染函数相耦合。解耦
// setInterval(() => {
//   // 虽然定时任务一直在跑,但是加载相同组件,react是不会重新初始化的。这也是时间没有更新的原因。
//   root.render(<Hello />)
// }, 1000);
root.render(<Hello />)

案例二:tab切换

  1. index.js
    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './App.css' 
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    
    class Tab extends React.Component{
      constructor(props){
        super(props)
         // 设置状态、数据
        this.state = {
          c1:'content-active',
          c2:'content'
        }
        this.clickEvent = this.clickEvent.bind(this)
      }
      clickEvent(e){
        console.log(e)
        console.log(e.target)
        let index = e.target.dataset.index
        console.log(index)
        // 这里必须在构造函数中对this进行绑定。否则这里的this是undefined
        console.log(this)
        this.setState({
          // 强等于
          c1: index === '1' ? 'content-active' : 'content',
          c2: index === '2' ? 'content-active' : 'content'
        })
      }
      render(){
        return(<div>
          <button data-index='1' onClick={this.clickEvent}>内容1</button>&nbsp;
          <button data-index='2' onClick={this.clickEvent}>内容2</button>
          <h1 className={this.state.c1}>内容1</h1>
          <h1 className={this.state.c2}>内容2</h1>
        </div>)
      }
    }
    
    root.render(<Tab />)
    
  2. App.css
    .content{
      display: none;
    }
    .content-active{
      display: block;
    }
    

React 数据传递

父传子

props:父组件给传子组件数据,单向流动,不能子组件传给父组件。
props的传值可以是任意的类型。
props可以设置默认值。语法:ComponentName.defaultProps = { param:value }
可以传递函数,从而修改父组件的state,从而实现子传父。

案例:

  1. index.js
    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './index.css'
    
    // 在父元素中使用state去控制子元素props的从而实现父传子。
    const root = ReactDOM.createRoot(document.getElementById('root'));
    
    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 strCls = this.props.isActive ? ' active' : '';
        return(<div className={'content' + strCls}>
          <h1>这是子组件</h1>
        </div>)
      }
    }
    
    root.render(<ParentCom />);
    
  2. index.css
    .content{
      display: none;
    }
    .content.active{
      display: block;
    }
    

子传父

调用父类传入的方法,给父类的方法传值,来实现子传父。

案例

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css'

// 子传父
const root = ReactDOM.createRoot(document.getElementById('root'));


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 : 'HELLO WORLD'
    }
  }
  render(){
    return(<div>
      <h1>这是子组件</h1>
      <button onClick={this.sendMsg}>传入数据</button>
      {/* 这里可以直接调用父元素的方法。但是要注意使用箭头函数 */}
      <button onClick={()=>{this.props.setChildData('')}}>重置</button>
    </div>)
  }
  sendMsg = ()=>{
    // 使用箭头函数,可以不用绑定。
    this.props.setChildData(this.state.msg)
  }
}

root.render(<ParentCom/>)

react 事件

  1. 特点:
    1. 驼峰命名,首字母小写,后续单词首字母大写。
    2. {}大括号括起来,传入一个函数。
  2. 事件对象:React返回的事件ui想是代理的原生的事件对象。如果需要查看事件对象的具体值,必须直接输出事件对象的属性。
  3. 事件默认行为:原生,组织默认行为的时候,可以直接return false。但是在react中阻止事件默认行为必须调用e.preventDefault()函数。
  4. react事件传参:需要使用箭头函数。
    <button onClick={(e)=>{this.envet2(123,e)}}>函数传参</button>
    

案例:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css'

// 子传父
const root = ReactDOM.createRoot(document.getElementById('root'));

class ParentCom extends React.Component{
  constructor(props){
    super(props)
  }
  render(){
    return(<div>
      <form action='http://www.baidu.com'>
        <a className='child'>HELLO WROLD</a>
        <button onClick={this.parentEvent}>submit</button>
      </form>
      <button onClick={(e)=>{this.envet2(123,e)}}>函数传参</button>
    </div>)
  }
  parentEvent=(e)=>{
    console.log(e)
    // 阻止事件默认行为。
    e.preventDefault()
  }
  envet2(param,e){
    console.log(param)
  }
}

root.render(<ParentCom />)

React 条件渲染

React中的条件渲染即和JS中,条件运算,eg:if...eles...(三元运算)boolean?res1:res2

  1. 通过条件运算返回要渲染的JSX对象
  2. 通过条件运算得出jsx对象,再将jsx对象渲染到模板中
  3. 通过修改样式active的方式。(这个案例在上面的例子中已经存在)

案例:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css'

// 子传父
const root = ReactDOM.createRoot(document.getElementById('root'));

function Welcom(props){
  return (<div>
    <h1>欢迎登录</h1>
  </div>)
}
function Login(props){
  return (<div>
    <h1>PLESE LOGIN</h1>
  </div>)
}

class Demo extends React.Component{
  constructor(props){
    super(props)
      this.state = {
        isLogin: false
    }
  }
  render(){
    return this.state.isLogin ? <Welcom/> : <Login />
  }
}

class Demo2 extends React.Component{
  constructor(props){
    super(props)
      this.state = {
        isLogin: false
    }
  }
  render(){
    let element = this.state.isLogin ? <Welcom/> : <Login />
    return(<div>
      <h1>----- HEAD -----</h1>
      {element}
      {this.state.isLogin ? <Welcom/> : <Login />}
      <h1>-----  END -----</h1>
    </div>)
  }
}

// root.render(<Demo1 />)
root.render(<Demo2 />)

React 列表渲染

将列表数据接成数组的JSX放置到模板中。
使用数组的map方法,对每一项数据按照JSX的形式进行加工,最终得到一个每一项都是JSX对象的数组,再将数组渲染到模板中,并将key值放置到数组中。

案例

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css'

// 子传父
const root = ReactDOM.createRoot(document.getElementById('root'));

function List1(props){
  let item = props.item
  console.log(item)
  return (<li>
    <strong>{item.name}</strong>-<span>{item.age}</span>
  </li>)
}

class List2 extends React.Component{
  constructor(props){
    super(props)
  }
  render(){
    let item = this.props.item
    return(<li onClick={(e)=>{this.clickEvent(this.props.index,item.name,e)}}>
        <strong><a>{item.name}</a></strong>
        -<span>{item.age}</span>
    </li>)
  }
  clickEvent=(index,name,event)=>{
    alert(index+"-"+name)
  }
}

class Demo extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      list:[
        {
          name: 'Huathy',
          age: '22'
        },
        {
          name: '小花',
          age: '18'
        },
        {
          name: '嘻嘻',
          age: '20'
        }
      ]
    }
  }
  render(){
    let arr = this.state.list.map((item,index) => {
      return(
        // <li key={index}>
        //   <strong>{index}:{item.name}</strong>-<span>{item.age}</span>
        // </li>

        <List1 key={index} item={item} index={index}/>
      )
    })
    return(<div>
      <h1>利用组件1的方式</h1>
      <ul>
        <li>
          <strong>name</strong>-<span>age</span>
        </li>
        {arr}
      </ul>
      <h1>利用组件2的方式</h1>
      <ul>
        {
          this.state.list.map((item,index)=><List2 key={index} item={item} index={index}/>)
        }
      </ul>
      <h1>不利用组件的方式</h1>
      <ul>
        {
          this.state.list.map((item,index)=>(<li onClick={(e)=>{this.clickFn(index,item.name,e)}} key={index}>
            <strong>{item.name}</strong>-<span>{item.age}</span>
          </li>))
        }
      </ul>
    </div>)
  }
  clickFn = (index,name,event) => {
    alert(index+"-clickFN-"+name)
  }
}

root.render(<Demo/>)

For循环方法

  1. forEach:没有返回值
arr.forEach( ( item,index ) => { } )
  1. map:对数组每一项进行加工后返回一个新数组
let arr = [1,2,3,4,5,6]
let res = arr.map((item,index)=>{
	let str = item+index
	return str
})
  1. filter:过滤,将想要的内容进行筛选,返回筛选后的内容
let arr = [1,2,3,4,5,6]
let res = arr.filter((item,index)=>{
	return item%2 == 0	//返回偶数,过滤奇数
})
  1. reduce:对数组进行整合
let arr = [1,2,3,4,5,6]
let res = arr.reduce((pre,next)=>{
	return pre + next
})
  1. for...in...主要用来遍历对象,不适合遍历数组
let obj = {name:'Huathy',age:18}
for (key in obj){	//key是无序随机的
	console.log(key+'-'+obj[key])
}
  1. for...of...可以用来遍历数组、类数组的对象、字符串、set、map
let arr = [1,2,3,4,5,6]
// 与for...in...的区别是of的item是元素值,而in的key是键名
for(let item of arr){
	console.log(item)
}

说明:个人学习笔记,对视频内容有所调整删减。以使得文章更简洁。
致谢:B站UP主[老陈打码] BV1T7411W72T
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Huathy-雨落江南,浮生若梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值