react 入门(一)

227 阅读10分钟

一:安装运行和初识

zh-hans.reactjs.org/docs/render…

1:react脚手架 对项目进行开发部署

1:安装脚手架
 npm i -g create-react-app
2:创建项目
create-react-app 项目名称
3:启动项目
cnpm start

或者

npx create-react-app 项目名
cd 项目名
npm strat

2:项目初次生成目录结构

yarn.lock:项目依赖的安装包版本号会在这里做一些限制。

README.md:关于项目的说明文件。

package.json:node的包文件,关于项目的一些介绍及一些项目的指令等。

gitignore:如果项目是用git管理的,有些文件不想上传到git仓库里,可以把文件定义到该文件中。

node_modules:项目依赖的第三方的包,是脚手架实现自己功能依赖的一些外部的文件。

public 文件夹下:

favicon.ico:项目图标,可以自己制作一个ico图标,取名为favicon.ico,覆盖该文件。

index.html:项目的首页。

manifest.json:定义网页快捷方式。

src目录下:

index.js:整个程序的入口文件。

registerServiceWorker.js :(pwa)用户第一次访问网页需要联网,下次即使断网,也依然可以显示。

​                                               如果有内容需要缓存,就会给缓存起来

App.test.js:项目测试文件。组件的测试

setupTests.js  相对于index.js的测试

3:必要的项目结构

public  : 放公共的静态资源
src : 放用户写的代码
package.json

App.js 是项目第一个页面,可以修改这个文件,查看页面效果
index.js 是项目的入口

二:jsx语法

  1.介绍:JSX,是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。
  2.语法说明:
    jsx语法: js语法 + html语法
    只要遇到标签,比如:<div></div>,这时按html语法解析
    只要遇到{},这时就按js语法解析,{}中可以放变量,表达式
    <div>{username}</div>
  3.注意:
    1.jsx语法中如果标签需要添加类名,这时需要使用 className 属性
    2.tabindex 则变为 tabIndex(是html属性 tabindex 属性规定元素的 tab 键控制次序(当 tab 键用于导航时)。)
    3.添加js注释,需要添加到{}中,比如{ /* 注释内容 */}

三:渲染函数

一个元素:
const element = <h1>Hello, world</h1>;

将一个元素渲染为DOM:
使用ReactDOM的render函数
ReactDom.render(<组件/ >,document.getElementById('root'))

const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));

四:组件和props

组件

!!!!!注意:1.组件名称必须以大写字母开头
              2.调用ReactDom.render(<Welcome />)时,组件是以标签形式调用的,写单标签时必须有结束符号
              3.组件调用可以不在ReactDom.render方法中,可以在页面中任何位置
   细节说明:
        1.functionclass 关键字后的名称就是组件名称。
        2.return 后就是页面结构,如果页面结构比较复杂,需要使用小括号括起来
        3.return 后的页面结构,只能有一个顶级标签,顶级标签不能有兄弟元素
        4.组件是页面结构,如果这个组件有自己的css样式,在当前组件中通过import引入
        

   props 使用分两步:
    1.组件调用时,组件上通过定义属性,传递数据
    2.组件内部通过 this.props.属性名称 得到传递的值
    
      举例:调用:<About username="jim" upwd='k123' />
            定义:class About extends React.Component{
                render(){
                    return (
                        <div>
                            <p>姓名:{this.props.username}</p>
                            <p>密码:{this.props.upwd}</p>
                        </div>
                    )
                }
            }
    3.props是单向传递,也就是说只能从父组件传到子组件,子组件传递给父组件时,不能使用 属性传递的形式props传回去
    4.props是只读属性
    拿到值后做任何操作都不可改变props对象上的值,当然你可以使用它赋值去做其他改变

1:定义组件的方式有两种:

1:函数形式

function ListItem(props) {
  console.log(props);
  return (
   <div>这是一个函数式的组件</div>
  );
}

2:class类形式的

  class ChildrenCom extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      msg: "helloworld",
    };
   }
  render() {
    return (
      <div>
           这是一个class式的组件
      </div>
    );
  }

}

3:导出

  export default 组件

2:使用组件

1:引入 import '组件' from '地址'

props

调用组件时可以给组件传递参数,props是用来接受传递过来参数的一个属性

组件之间的传值

知识点: state props setState({})

父组件传递数据给子组件
// 父传子

// 注意:props可以传递函数,props可以传递父元素的函数,就可以去修改父元素的state,从而达到传递数据给父元素。
// 在父元素中使用state去控制子元素props的从而达到父元素数据传递给子元素
class ParentCom extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      fatherToChild: "hello",
    };
   }

  render() {
    return (
      <div>
        <button>
         父组件
        </button>
        <ChildrenDom FatherToChild={this.state.fatherToChild}></ChildrenDom>
      </div>
    );
  }
}

class ChildrenDom extends React.Component {
  constructor(props) {
    super(props);
    console.log("子组件的props", props);
  }
  render() {
    return (
      <div>
        <h1}>这个是子组件{FatherToChild}</h1>
      </div>
    );
  }
}


子组件传递数据给父组件
  
// 调用父元素的函数从而操作父元素的数据,从而实现数据从子元素传递至父元素

class ParentCom2 extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      childData: null,
    };
  }
  render() {
    return (
      <div>
        <h1>子元素传递给父元素的数据:{this.state.childData}</h1>
        <ChildrenCom setChildData={this.setChildData}></ChildrenCom>
        {/* 把函数传递给了子组件,子组件可以在props看到 ,可以调用 */}
      </div>
    );
  }

  setChildData = (data) => {
    this.setState({
      childData: data,
    });
  };
}
class ChildrenCom extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      msg: "helloworld",
    };
    // this.sendDate = this.sendDate.bind(this)
  }
  render() {
    return (
      <div>
        <button onClick={this.sendDate}>传递helloworld 给父元素</button>
        <button onClick={()=>{this.props.setChildData(this.state.msg)}}>传递helloworld 给父元素</button>
      </div>
    );
  }
  sendDate = () => {
      //将子组件传递给到父组件,实际上时调用父组件的传递进来的方法
    this.props.setChildData(this.state.msg);
  };
  //   sendDate(){
  //       console.log(this);   //undefined  需要搭配 this.sendDate = this.sendDate.bind(this)  去绑定this指向
  //   }
}

五: 生命周期函数和state

每一个组件从创建到销毁,过程中会有一些自动执行函数,被称为生命周期函数

   componentWillMount(){}       组件将要渲染
   
   render(){}                   渲染功能
   componentDidMount(){}         组件渲染完毕,组件会进入运行状态
   
   componentWillReceiveProps     props发生改变触发
   shuouldCompoentUpdate(){       是否允许组件发生改变
     return true   允许组件发生改变
     return false  是禁止组件发生改变
   }
    
    componentWillUpdate(){}       组件状态将要发生更新
    render(){}                    渲染功能,这是刚更新页面
    componentDidUpdate(){}        组件状态完成更新,再次进入运行状态  
    
    componentWillUnmount(){}        组件将要销毁
    
    
   进行网络请求时,可以将请求的代码写在 componentWillMount和componentDidMount两个生命周期函数中 
   
   区别在页面表现形式:
   
   componentWillMount:如果网页加载很慢的情况下,会出现白屏,因为组件还没有渲染
   
   componentDidMount  :render完之后,已经加载页面,动态加载数据的部门先空着,稍后慢慢填充
   
   所以一般情况下我们要放在componentDidMount中,除非有特殊情况
   
   举个例子,比如我们的登录,此页面已经登陆过了,当再次打开页面时,直接在右上角显示用户名,不必让页面闪一下(留有一个空白),才能显示用户名。这就是在componentWillMount中的
   
   网速慢得时候先显示请登录,过了一会显示了用户名的情况就是将请求放在了componentDidMount中
   
    根据需求不用,调用不同的生命周期函数
    

   
    生命周期内部的this ,指向的是 当前的组件
    

state

state
    1.state是组件内部的状态,外部不可访问。
    2.使用:
        1.需要使用es6的class定义组件
        2.class定义组件中添加,state在constructor中初始化
            constructor(props) {
                super(props);
                this.state = {date: new Date()};
            }
        3.组件内部就可以使用state了
            访问:this.state.属性
            修改:this.setState({
                        属性名:属性值
                    })
                    
                  如果更新是异步的,则setState接受一个函数,而不是一个对象
                 setState((state)=>{   
                                   })
                    

六: 事件处理

1.给元素绑定事件
2.React 事件的命名采用小驼峰式(camelCase),而不是纯小写
  使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串
3.使用:

    <div onMouseOver={this.函数名.bind(this)}></div>

​    1.on+事件名称,形成事件
​    2.事件={},大括号中写事件函数,还需要使用bind()把this绑定到当前函数
​    3.函数定义在class类中,和生命周期函数同级
​        demo(a,b,event){

​    }
4.函数调用也可以传参,bind(this,参数1,参数2)
5.事件对象在函数定义中写,有一个关键字叫event
6.不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault
7.给事件函数绑定this的第二种方式:在构造函数中初始化
​    constructor(){
​        this.demo = this.demo.bind(this)
​    }
​    demo(){

​    }

七:条件渲染

实现方式

if、三元表达式

运算符 &&等

八:列表渲染

1.用循环生成页面结构,并填充数据
2.循环生成的元素上要添加key,用来表示是唯一的。
3.使用:
    map() 实现遍历
    数组.map(function(element,index){
        element是元素项
        index是下标
    })
4.数组遍历方法
    for()
    map()
    filter()

九:表单

 1.表单分受控组件和非受控组件
        受控组件: state 为“唯一数据源”,setState唯一管理数据
        非受控组件:非受控组件将真实数据储存在 DOM 节点中

   
    2.受控组件
        1.<input>、 <textarea> 和 <select>
        2.使用:如何获取值以及更新值
            <input name="username" value={this.state.username} onChange={this.gaibian.bind(this)}>  
            方法1:使用value值获取和更新值
            gaibian(event){
                this.setState({
                    username:event.target.value
                })
            } 
            方法2:使用event上的属性target,通过name属性获取和更新值
            gaibian(event){
                this.setState({

    [event.target.name]:event.target.value

    ​            })
    ​        }
    ​    3.<textarea> 不管是设置值还是获取值都使用value属性
    ​    4.<select value={this.state.key} onChange={this.sel.bind(this)}> 
    ​        sel(event){
    ​            this.setState({
    ​                key:event.target.value
    ​            })
    ​        }
    ​    5.单选按钮
    ​        <input type="radio" name='sex' value='nan' onChange={this.selsex.bind(this)}/> 男 
    ​        <input type="radio" name='sex' value='nv' onChange={this.selsex.bind(this)}/> 女

            selsex(event){
                // console.log(event.target.value)
                this.setState({
                    sex:event.target.value
                })
            }
        6.多选按钮
            <input type="checkbox" vaule="apple" onChange={this.friut.bind(this)}>
            <input type="checkbox" vaule="orange" onChange={this.friut.bind(this)}>
            <input type="checkbox" vaule="pie" onChange={this.friut.bind(this)}>
        
            friut(event){
                let cur = event.target.value;
                let arr = this.state.shuiguo;
                if(this.state.shuiguo.indexOf(cur) == -1 ){
                    arr.push(cur)
                    this.setState({
                        shuiguo:arr
                    })
                }else{
                    arr.splice(this.state.shuiguo.indexOf(cur),1)
                    this.setState({
                        shuiguo:arr                
                    })
                }
            }
        7.form标签上
            <form onSubmit={this.tijiao.bind(this)}>
                <input type="submit"  value="提交" />
            <form>




  
  
3:非受控组件

  1. 非受控组件,这时表单数据将交由 DOM 节点来处理

  2. ref
   通过ref可以获取到DOM节点。
   定义方式:
       1.过时的语法:ref="字符串名称"

           <div ref='str'></div>

   ​    2.新语法:
   ​        创建ref: this.demo = React.createRef() 

           <div ref={this.demo}></div>  

   调用:
       过时的语法:this.ref名称.属性
       新语法:this.ref名称.current

十: 状态提升


1. 通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。

2. 实现方式:
   1.把父级的函数传递给子级
   2.在子级中调用父级函数,这时修改的是父级中的状态
   3.看到的效果是:所有引入父级这个状态的组件中的值都发生改变。

十一 :组件组合(vue中叫插槽)

1.包含关系(插槽)
    1. 在调用组件时,在组件标签内部添加其他代码
    2. 在组件内部,通过{this.props.children} 能获取到添加代码
    调用:
    <FancyBorder color="blue">
        <h1 className="Dialog-title">
            Welcome
        </h1>
        <p className="Dialog-message">
            Thank you for visiting our spacecraft!
        </p>
    </FancyBorder>
    定义:
    class FancyBorder extends React.Component{
        render(){
            return(
                <div>
                    {this.props.children}
                </div>
            )
        }
    }
    

十二:网络请求数据



1. fetch请求
   1.Fetch API 提供了一个 JavaScript接口,用于访问和操纵HTTP管道的部分,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
   2.语法:
       fetch(url,{
           method:'get',
           headers:{
               "content-type":"application/x-www-form-urlencoded"
           },
           body:"uname=key&upwd=123",
           credentials:"include, same-origin, omit", //是否允许携带cookie
           mode: 'no-cors, cors, same-origin' // 是否允许cors跨域
       })
       .then(function(data){
           return data.json()  // 解析数据
       })
       .then(function(res){
           console.log(res)    //请求到的结果
       })

2. 如果是post请求,传递数据格式是:"key=value&key=value"
   {
       user_id:"iwen@qq.com",
       password:"iwen123"
   }
   => "user_id=iwen@qq.com&password=iwen123&verification_code=crfvw"
   
nodejs中已经封装好一个组件,querystring
      querstring.parse("user_id=iwen@qq.com&password=iwen123") 
           =>{user_id:"iwen@qq.com",password:"iwen123"}

       querystring.stringify({
           user_id:"iwen@qq.com",
           password:"iwen123"
       })
           =>"user_id=iwen@qq.com&password=iwen123"

十三: 跨域

   解决方法:
   
    1.cors  :后台配置
    
    2.jsonp :
        下插件:fetch-jsonp
        使用插件
        
   3. 代理
          参考地址:https://github.com/facebook/create-react-app/blob/45bc6280d109b7e353ffaa497a0352c9d040c36d/docusaurus/docs/proxying-api-requests-in-development.md
       
       --------------------------------------------------------------------------------------------
        create-react-app 这个一键搭建环境命令生成的代码也可以实现代理
   原先通过fectch请求这个路径fecth('http://localhost:3001/user')。可使用代理方式有两种如下: 
       1.package.json文件中配置
           1.配置
        {
            "proxy": "http://localhost:3001"
        }
          2.重启服务器
          3.修改fetch请求中的路径
            fetch('/user')
            .then(data=>data.json())
            .then(res=>{
                console.log(res)
            })
    
      2.使用中间件
          1.下载:npm install http-proxy-middleware --save
          2.在src目录下创建setupProxy.js文件
          3.在setupProxy.js文件中配置
            const proxy = require('http-proxy-middleware');

            module.exports = function(app) {
                app.use(proxy('/*', { target: 'http://localhost:3001/' }));
            };
        4.重启服务器