浏览器依然不认识es6模块化语法,需要使用babel将es6的语法转成commonjs,然后通过browserify转成浏览器认识的语法
导出:
分别导出: export 值
统一导出: export {值,值}
默认导出: export default 值 默认导出在一个模块中只能写一次
导入
分别导出和统一导出都是
import {
值} from "路径/包"
默认导出
import 变量名自定义 from "路径/包"
就是将前端代码(js,css,html…)打包成静态资源的打包工具
五个核心概念:entry(入口),output(输出),loader(加载器),plugin(插件),mode(模式)
entry:指定入口文件
output:指定打包后的文件放在那里
loader:webpack只能处理js和json,如果需要处理其他文件,需要使用loader
plugin:如果loader不能完成某个功能,可以使用插件
mode:指定环境 development(开发环境) production(生产环境)
webpack配置文件的名称:webpack.config.js(定义在项目的根目录)
webpack配置文件主要写两个
开发环境:webpack.dev.js 需要配置devServer 帮助开发者自动编译刷新
开发环境,配置了devserver,实际上启动之后,在内存中创建了dist文件夹
生产环境:webpack.prod.js 不需要配置devServer
生产环境,当我们将所有的代码写完,测试完毕,直接打包项目,得到硬盘上的一个dist文件夹,直接将这个文件夹交给运行上线
当我们配置了两个配置文件,启动的时候,就不能直接使用webpack
需要在package.json中配置scripts
{
"scripts": {
"start": "webpack-dev-server --config ./config/webpack.dev.js",
"build": "webpack --config ./config/webpack.prod.js"
}
}
如果配置了package.json 开发环境启动项目,以及生产环境打包dist文件夹都不需要直接输出webpack/webpackdevserver 而是使用npm
npm run start —简写— npm start
npm run bulid
react是一个用于构建用户界面的js库
react 提供一些核心的api
react-dom 提供了一些dom的api
babel 将jsx转成浏览器认识的代码
React.createElement()通过这个函数,创建了react元素(虚拟dom),然后react底层会根据这个虚拟dom创建真实dom,然后渲染到页面上
ReactDOM.render()这个函数真正将虚拟DOM渲染到页面上
javascript xml 是js中的一个语法糖
可以让我们在js中直接写标签
create-react-app
方式一:
npm i create-react-app -g
create-react-app 项目名称
方式二:
npx create-react-app 项目名称
注意:
public文件夹下面至少要有一个index.html
src文件夹下面至少要有一个index.js
import React from "react"
import ReactDOM from "react-dom"
ReactDOM.render()
其实就是将结构和数据封装封装到一个js文件中 实现复用
function Module() {
return div}
class Module extends React.Component{
render(){
return div
}
}
定义状态
constructor(){
super()
this.state = {
count : 0;
}
}
获取状态
this.state.count
修改状态
this.setState({
count:值})
使用组件
<Module/>
注意点:
首字母要大写
返回的结构必须有一个根标签
当成标签去使用
问题原因:
事件处理函数,底层执行的时候是普通调用,这时按道理this应该指向windows
由于代码被babel编译过,成为了严格模式,所以指向undefined
解决办法
1.箭头函数
箭头函数 () =>{
}
2.bind
// 给当前组件实例增加了一个handle方法,这个方法的this被固定指向了当前组件实例
constructor(){
super()
this.handlexxx = this.handle.bild(this)
}
3.ES7新的语法(类的实例方法)
handlexxx = () => {
}
作用:接收组件外部数据
如何传递:
如何接收?
类组件
this.props.xxx
函数组件
function Header(props){
return <div>{
props.xxx}</div>
}
props效验
使用组件时,传入的数据不对,可以报出更清晰的错误
import PropTypes from "prop-types"
组件.propTypes = {
属性.PropTypes.string.isRequired
}
默认props
组件.defaultProps = {
}
props的特点
props是只读属性,不要给props赋值
受控组件
表单项的值,被组件的状态所控制,想要获取表单项的值,直接从状态中获取
文本框/下拉框/文本域/单选框 直接通过value属性控制,复选框,用checked属性控制
都要配合onchange事件,在这个事件里面,获取用户输入添加到状态中
非受控组件
直接操作dom
使用Reac.createRef() 得到的ref对象和标签绑定
<input ref={
ref对象}>
获取真实dom ref对象.current指向真实dom
// 原始写法
function fn(name){
return (e)=>{
}
}
// 简写
let fn = name => e =>{
}
如果多个组件,都使用同一份数据,这个数据应该放到他们的父组件中
props
父=>子 用props传
子=>父 父组件中定义函数,将函数传递给子组件,子组件调用函数,将数据当做实参传递给父组件
context
注意:保证是同一个context对象
一般只用来传递一些简单的数据
自上而下跨级传递数据
创建context对象 React.createContext(“默认值”)
在传递数据的组件中写Provider组件 value属性的值就是要传递的数据
<Provider value={
要传递的值}>
<div className="App">
<Child1 />
</div>
</Provider>
在使用数据的组件中写consumer组件
<Consumer>{
data => <span>data参数表示接收到的数据 -- {
data}</span>} </Consumer>
第二种使用方式,给组件添加静态属性contextType
export default class Demo extends Component {
// 给要使用的Context的Demo类,添加静态contextType属性, 并赋值为context对象
// 那么在Demo的实例对象上context属性中就可以获取到需要的值
static contextType = MyContext
render() {
// return {data => {data}
}
return <div>{
this.context}</div>
}
}
// 下载包
npm i pubsub-js
// 导入
import PubSub from "pubsub-js"
//api
PubSub.publish("话题",数据)
PubSub.subscribe("话题",("话题",数据)=>{
}) 组件挂载成功的时候写
PubSub.unsubscribe(token/话题)取消订阅 组件卸载的时候取消
创建阶段
constructor 定义状态
render 返回结构
componentDidMount 订阅pubsub发送请求/操作dom
更新阶段
render 注意:不要在这里调用setStat,否则递归死循环
componentDidUpdate 注意:如果一定要调用setState:需要给if给个出口
卸载阶段
componentWillUnMount 取消订阅/取消定时器/取消一些dom原生的事件
<React.Fragment></React.Fragment>
<></> 包裹结构,但是不会渲染根标签
1.减轻state,跟视图无关的数据,不要卸载state里面,可以直接加到this上面
2.shouldComponentUpdate 返回true,组件才更新,返回false,组件不更新
shouldComponentUpdate(nextProps,nextState)
// 判断state和props是否变化,有一个变化了才更新,否则不更新
3.PrueComponent(纯组件)
底层帮我们写了shouldComponentUpdate,但是是浅层对比
注意:修改状态的时候,不要直接在原来的数据的基础上修改,应该根据原来的数据,得到一个新的数据,修改新的数据
作用:将多个组件中公用的状态和逻辑封装起来,实现复用
写法:
// 1.定义一个函数
function withXXX(WrappedComponent){
return class extends Component{
...定义公共状态和逻辑
}
render(){
return (
<wrappedComponent {
...this.state}{
this.props}/>
)
}
}
使用
const 新的组件 = withXXX(需要使用状态和逻辑的组件)
然后渲染的是新的组件
问题
1.传递props的问题:在封装的高阶组件里面直接将props传递下去
2.在react-dev-tool中,展示高阶组件名字的时候不清晰 给高阶组件加一个静态属性static displayName
作用:将多个组件中公共的状态和逻辑封装起来,实现复用
写法:
// 1.定义一个组件
class XXX extends Component{
...定义状态和逻辑
render(){
// return this.props.render(数据)
return this.props.children(数据)
}
}
// 2.使用
<Position render={
data => 需要使用状态和逻辑的组件}><Position>
<Position>{
data => 需要使用状态和逻辑的组件}</Position>
hooks的作用:
在函数组件中,可以使用类组件的一些功能(比如:可以定义状态或定义生命周期的钩子函数)
常用的hooks
useState(在函数中定义状态)
// 导入
import {
useState} from "react"
// 使用
const [状态的属性,操作状态的方法] = useState(初始值) 可以使用多次
useEffect(在函数组件中模拟生命周期钩子函数)
// 导入
import {
useEffect} from "react"
使用:
useEffect(()=>{
},[])
第一个回调函数,默认模拟componentDidMount和componentDidUpdate
如果第二个参数传入的是空数组,第一个回调函数只模拟componentDidMount
如果在第二个参数的数组中,监听的数据,那么当监听的数据发生变化的时候,第一个参数的回调函数也可以模拟componentDidUpdate
useEffect(()=>{
return ()=>{
}
})
第一个参数的回调函数中,可以返回一个回调函数,这个回调函数模拟的是componentWillUnmount
hooks使用的规则
1.不管是react提供的hooks,还是第三方的hooks,还是自己定义的hooks,都遵守下面的规则
2.规则
hooks只能在函数组件和自定义hooks中使用
在函数组件和自定义hooks中使用其他hooks的时候要求写在顶级作用域,千万不要写在if/循环/嵌套的普通函数中
3.自定义hooks
看起来就像是一个普通的函数 自定义hooks的名字都应该是useXXX
是一个状态管理的js库
集中管理数据
实现方式 : {
type:"INCREMENT"}
// 实现方式:函数
function fn(state={
xxx:"默认值",action}){
switch(action.type){
case 需求:
return 最新数据
default:
return state
}
}
注意:reducer在创建store的时候会被调用一次,这次调用会走default,用来初始化redux中的数据
每一次调用dispatch的时候,reducer也会被调用,redux会自动将最新的数据传递给state参数,将需求传递给action参数
const store对象 = createStore(reducer函数)
const store对象 = createStore(reducer函数,applyMiddleware(中间件,中间件.中间件)) 如果要使用中间件
一般分成四个文件去写
1.actions.js 在这里定义同步的action和异步的action
2.constants.js 定义一些常量(需求类型)
3.reducer.js 定义reducer函数
4.store.js 创建store
展示组件,其实就是react组件
通过props,去获取redux的数据和操作redux数据的方法
容器组件,就是使用connect函数得到的组件
职责::将redux中的数据和操作redux数据的方法,传递给展示组件
// 导入Provider
import {
Provider} from "react-redux"
<Provider store={
store}>
<WithList></WithList>
<Provider>
// 包裹其它组件和结构,包裹的同时,传递store对象
// 导入connect组件
import {
connect} from "react-redux"
// 导入展示组件
import List from "./page/List"
// 导入操作redux数据的方法(异步action)
import {
getUserAsync} from "./redux/actions"
const WithList = connect(state => {
{
users:state.users}},{
getUsersAsync})(List)
export default WithList
const 容器组件 = connect(传给展示组件的数据,传给展示组件操作redux数据的方法)(展示组件)
对于connect函数的描述
//connect函数,内部结构
function connect(){
return function(){
return class extends Component{
}
}
}
后面如果redux中数据发生了变化,react-redux还会继续调用这个函数,将最新的数据传递给真实的组件,所以在展示组件中永远可以自动获取到最新的数据
第二个参数:
传入一个对象{actionCreator,actionCreator}
注意:在展示组件中,可以获取到相同名称的函数,但是在展示组件中拿到的函数,不是真正的actionCreator,只是名字相同而已
connect函数将传入的actionCreaor进行了一次封装
比如actionCreator的名字叫做inc connect会根据合格inc新建一个函数
function inc(){
//这个inc是传递给展示组件的函数
diapatch(inc()) //这个inc是actionCreator
}
首先 redux中默认不支持异步操作
但是在实际开发中,经常要发送请求获取数据
需要利用redux-thunk去实现异步操作
使用:
// 在action.js中定义一个异步action
function 异步antion名字(){
return dispatch =>{
//发送异步请求
//异步请求成功的时候
dispatch(同步action)
}
}