React学习笔记之二---主要组件

慕容恩
2023-12-01

特点:

  • 使用命令create-react-app my-app生成基础项目之后会导入两个基础框架:react和react-dom ,同时也会使用webpack自动集成一些框架,这些框架可以在node_modules文件目录下找到。
  • 生成项目后,脚手架为了优雅,隐藏了所有的webpack相关的配置文件,此时查看my-app(你的项目文件)文件目录,会发现找不到任何webpack配置文件,这也导致了如果我们需要在webpack安装一些自己的loder或者plugin变得比较困难。

自动安装的主要组件及其作用

组建名称主要作用
reactreact的核心代码
react-dom特定的DOM操作
eslint代码检测
url-loaderBASE64图片(小于1000kb)
babel-loaderES6和JSX语法解析
style-loader、css-loadercss代码解析
HtmlWebpackPlugin产出HTML插件

一个完整的项目除开需要这些基础框架之外,还需要一些常用的组件:

redux:帮助解决state变化和异步,state可能暴扣服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括UI状态,如接货的路由,被选中的标签,是否显示加载动态效果或者分页器等等。

  • 单一数据源
    整个应用的state被存储在一棵object tree中,并且整个object tree只存在于唯一一个store中。
  • State是只读的
    唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象。
  • 使用纯函数来执行修改
    为了描述action如何改变state tree,你需要编写redducers。Reducer只是一些纯函数,它接收先前的state和action,并返回心动 state.

react-redux: Redux的作者封装了一个React专用的库React-Redux,React-redux将所有的组件分成两大类:UI组件和容器组件。

  • UI组件
    只负责UI呈现,不带任何业务逻辑,没有状态(即不适用this.state这个变量),所有数据都由参数(this.props)提供,不使用任何Redux的API.因为不含有任何状态,UI组件又称之为"纯组件",即它和纯函数一样,纯粹由参数决定它的值.
const Title = Value => <h1>{value}</h1>;
  • 容器组件
    与UI组件完全相反,负责管理数据和业务逻辑,不负责UI的呈现,带有内部状态,使用Redux的API
  • connect()
    用于从UI组件生成容器组件。connect的意思就是将这两种组件连接起来。
import { connect } from 'react-redux'
const VisibleTodoList = connect(
  mapStateToProps,  //输入逻辑,(即state对象)如何转换为UI组件的参数
  mapDispatchToProps //输出逻辑,用户发出的动作如何变为Action对象,从UI组件传出去。
)(TodoList)

TodoList是UI组件,VisibleTodoList就是由React-Redux通过connet方法自动生成的容器组件。

styled-component:样式化组件的主要作用是它可以编写实际的Css代码来设计组件样式,也不需要组件和样式之间的映射,即创建后就是一个正常的React组件,并且可以附加样式给当前组件。

  • nejectGlobal
    编写全局CSS的辅助方法,它不返回组件,而是直接将样式添加到样式表中,这跟我们平时写在html页面,会先把一些需要重置的浏览器的样式加到页面上的做法类似,主要作用是:重置样式及书写全局可用的共用样式。
import { injectGlobal } from 'styled-components';
injectGlobal`
  @font-face {
    font-family: 'Operator Mono';
    src: url('../fonts/Operator-Mono.ttf');
  }
  body {
    margin: 0;
  }
  • styledComponent
    样式化组件声明方式,styled.tagname、styled(Component)两种方式
    第一种直接通过styled点一个元素标签,将button元素转化成样式化组件
    第二种是重写样式化组件的部分样式,比如TomatoButton
  • extend
    创建一个新的StyledComponent并且继承它的规则,如:TomatoButton继承了Button的样式规则,并且使用一些与颜色相关的样式进行扩展(其实就是覆盖了被继承组件的某些样式)。
const TomatoButton = Button.extend`    
  color: tomato;
  border-color: tomato;
  • withComponent
    创建一个新的StyledComponent,并应用于其他的标签或组件,且使用相同的样式如:用标签替换标签,但还是使用相同的样式。
const Link = Button.withComponent('a')

History:history是一个管理js应用session会话历史的js库。它将不同环境(浏览器,node…)的变量统一成了一个简易的API来管理历史堆栈、导航、确认跳转、以及session间的持续状态。

  • location
    一个history知道如何去监听浏览器地址栏的变化,并解析这个URL转化为location对象,然后router使用它匹配到路由,最后正确地渲染对应的组件。
    location对象包括:
    pathname 同window.location.pathname
    search 同window.location.search
    state一个捆绑子这个地址上的object对象
    action PUSH,REPLACE,或者POP中的一个
    key 唯一ID

常用的三种History
a. hashHistory
不需要服务器配置,在URL生成一个哈希来跟踪状态,通常在测试环境使用,也可以作为发布环境使用。
b.browserHistory
需要服务端做配置,路径是真实的URL,是官方推荐首选。
客户端:
ReactDOM.render((//你的route),document.getElementById(‘root’));
import { Provider } from ‘react-redux’
import { Router, browserHistory } from ‘react-router’

服务端:
// 通常用于加载静态资源app.use(express.static(__dirname + ‘/public’))
// 在你应用 JavaScript 文件中包含了一个 script 标签// 的 index.html 中处理任何一个 routeapp.get(’*’, function (request, response){response.sendFile(path.resolve(__dirname, ‘public’, ‘index.html’))})
app.listen(port)console.log("server started on port " + port)
const express = require(‘express’)
const path = require(‘path’)
const port = process.env.PORT || 8080
const app = express()

browserHistory需要服务端配置的原因
因为真实的URL其实是指向服务器资源,比如我们经常使用的API接口,也是一个真实的URL的资源路径,当通过真实的URL访问网站的时候,第一次访问的是网站的域名,这个时候可以正常加载我们的网站js等文件,而用户手动刷新网页的时候,由于路径是指向服务器的真实路径,服务器端没有做路由配置,就会导致资源不存在,用户访问的资源不存在,返回给用户的是404错误。
通过hashHistory来生成的URL就不会出现这样的问题,因为它不是指向真实的路由。

Fetch:fetch被称为下一代Ajax技术,采用Promise方式来处理数据。Fetch的核心是HTTP Requests,Responses Headers和Bodypayload的接口抽象,以及一个用于启动异步资源请求的全局fetch方法。

  • 上传JSON数据
    使用fetch()开机自检JSON编码的数据
var url = 'https://example.com/profile';
var data = {username: 'example'};

fetch(url, {
 method: 'POST', // or 'PUT'
 body: JSON.stringify(data), 
 headers: new Headers({
   'Content-Type': 'application/json'
 })
}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));
  • 传文件
    可以使用HTML,input元素、FormData() 和fetch()来上载文件。
<input type="file"/> 
var formData = new FormData();
var fileField = document.querySelector("input[type='file']");

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then(response => response.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));
  • 提供自己的请求对象
    你可以使用Request()构造函数创建请求对象,并将其中作为fetch()方法参数传入,而不是将要请求的资源路径传递到fetch()调用中。
var myHeaders = new Headers();
var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg', myInit);

fetch(myRequest).then(function(response) {
  return response.blob();
}).then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

React-Router:路由是用于支持页面跳转的支撑。此模块比较重要且复杂,写法多样。如今React router已经到了V5版本,增加了基于React Hooks的一些API,比如UseParams、useHistory等,让我们可以在组件中不接受route props就可以拿到路由信息{match,location,location},除了利用React Hooks,React router中还有其他充分展示了React特性的API,比如利用了render props,withRouter利用了高阶组件。另外,就像React家族中的其他成员一样,React Router也做了核心库和绑定库分离,在黑辛苦React Router核心库,有绑定

  • 用于web端的React-router-dom
  • 用于React Native的react-router-native
  • 用于Redux的react-router-redux
  • 配置静态路由的react-router-config.

由于路由比较复杂而且相对独立,详细资料请看 React学习笔记之三—路由

 类似资料: