核心库
react、react-dom、react-router-dom、react-redux、redux
脚手架
create-react-app
基础知识
jsx是什么
- jsx是js的语法糖,可以在js中编写xml,类似xml,可自定义标签;
- jsx不是HTML,也不是字符串;
- 标签名要求全部小写;
- 组件名首字母大写;
- 他可以配合js表达式一起使用;
- 所有标签要闭合,哪怕是单标签;
- jsx中必须有一个顶层包含容器(不想输出标签,可以使用<></>,)
插值表达式是什么
接受的是一个js表达式,运行之后会有一个值的运算就是表达式,如变量、运算和函数调用
不同类型值的表现
- 字符串、数字,原样输出
- 布尔值、未定义、空会被忽略
- 对象,不能在内容里直接输出
- 数组:字符串拼接输出
条件渲染
|| 、&& 、 ?:
列表渲染
{ list.map((item)=>{}) }
jsx中的特殊属性
- className、htmlFor、style必须是一个对象:{{}}
- dangerouslySetHTML,可以让我们设置动态设置元素的 innerHTML
render () {
return (
<div
className='editor-wrapper'
dangerouslySetInnerHTML={{__html: this.state.innerHTML}} />
)
}
组件
在react中,会把视图拆分成若干的组件,如按钮、列表、等等 分为两种:类组件和函数组件
类组件
- 必须继承自Component或者PureComponent
- 拥有render方法
组件的视图更新
- state 状态,通过setState更新状态,会引起组件更新(视图重新渲染)
- props状态,父组件props改变,子组件重新渲染
事件
- 注意事件名是小驼峰
- 事件处理函数的this默认是undefined,可以使用箭头函数或this绑定
setState
setState(updater, [callback])
- updater: 更新数据 FUNCTION/OBJECT
- callback: 更新成功后的回调 FUNCTION
- 异步:react通常会集齐一批需要更新的组件,然后一次性更新来保证渲染的性能
- 浅合并 Object.assign(),只会修改需要修改的状态
- 调用setState之后,会触发生命周期,重新渲染组件
- setState是一个异步方法,调用setState修改状态,并不会立马修改组件的状态,而是进入一个更新流程,在更新过程中修改state 注意:setState是同步还是异步,可参考setState到底是同步还是异步
组件间通信
- 父传子 props,单向数据,从上到下
- 子传父--函数回调
- 兄弟之间 context provider consumer contextType
- 第三方库 redux、react-redux、mobx、unstated等等
组件生命周期
挂载阶段
- constructor(props) --props为父元素传过来的属性
- static getDerivedStateFromProps --衍生状态,将props中的某些数据关联到状态中-接受props,静态方法是类的方法,不是实例的方法,不需要实例化就可以拿到
- render--调用render方法,根据render方法的返回值,生成vdom
- componentDidMount --组件挂载完成,可以获取真实Dom
更新阶段
- static getDerivedStateFromProps(props)
- shouldComponentUpdate(nextProps, nextState),如果组件继承自pureComponent,则已经包含了shouldComponentUpdate
- render()
- getSnapshotBeforeUpdate(prevProps, prevState),获取更新前的DOM快照,这一步组件即将去更新视图
- componentDidupdate(prevProps, prevState, preDom),组件更新完成
- preDom为getSnapshotBeforeUpdate返回的值
卸载阶段
componentWillUnmount() --取消订阅的事件、定时器等等副作用
函数组件
- 函数组件更新时,是整个函数重新执行
- return返回我们要构建的视图
- react 16.7之前没有state和生命周期,16.8开始使用hooks
常用hooks(钩子函数)
const [state, setState] = useState(initstate)
const [状态,修改状态的方法] = useState(初始值)
- 在同一个组件可以使用多个useState定义多个状态
- 注意useState返回的setState方法不会进行对象合并
- 注意useState返回的setState方法同样是异步方法
useEffect**(()=>{},[依赖参数])
处理副作用 DOM操作,异步处理
- 没有依赖参数时,每次更新都会执行
- []时,挂载完成执行一次
- [依赖参数],依赖参数更新时,执行
- 卸载时,返回函数,清除副作用
useRef
- 用户关联原生DOM,或者用来记录组件更新前的数据
- 当useRef存储的是数据,而非获取DOM或者组件实例时,原数据改变,ref中存储的数据并不会随之改变,需要我们手动改变,通过ref的该特性就可以跨组件的更新阶段传递信息,换句话说,我么可以通过ref来获取组件更新前的信息
hooks使用规则
- 只能在函数组件中使用
- 只能在最顶层使用
- 不能在条件内使用
- 不能在内部函数使用
hooks优势
- 简化组件逻辑
- 复用状态逻辑
- 无需使用类组件编写
路由-router-单页面应用
分类
- HashRouter
- BrowserRouter
核心库
react-router-dom
route路由
根据url去匹配不用的视图
- path默认模糊匹配,即当前url以path开始时,即匹配成功
- exact:true 精确匹配
- strict:严格匹配
- component/render()=>{}/children(三种方式的区别)
route调用视图的三种方式
- component 通过组件直接调用
- render 接受回调函数,回调函数的返回值中定义该route要渲染的视图
- children
其他路由组件
- Link 本身是处理过的a标签
- Switch 按照顺序去匹配,匹配成功,则停止匹配
- NavLink 默认模糊匹配
- activeClassname=‘link’
- activeStyle
- isActive
- Redirect重定向
路由参数
history
- go(n)
- goBack(n)
- goForward(n)
- push(url, state) 不刷新切换路由
- length 当前历史记录项长度 location
- hash:’’ 当前url的hash值
- pathname:’’
- search:’’
- state: ’‘ push方法传的参数
match-当前路由的匹配信息
- isExact
- params -动态路由传递的参数
- path
- url
动态路由
/list/:id
动态路由在定义path时,路由中某一段可能是非固定的值,不能用精确匹配
路由动画库
react-transition-group
非路由导航中,获取路由参数
- 高阶路由
newCmp = withRouter(cmp),适用于类组件和函数组件
- router提供的hooks钩子是router 5之后才有的,只能用在函数组件中
- useHistory()-获取history对象
- useLocation()-获取location对象
- useParams()-获取动态路由参数
- useRouterMatch()-获取match对象
redux使用
redux是js的状态容器,提供可预测化的状态管理工具
核心api
- createStore --可创建store(仓库),
- combineReducer --可合并多个reducer,多个reducer中type也不能重名,所以命名最好:reudcer_type,const store = createStore(reducer)
- getState --store.getState() 可以获取到当前state
- dispatch --store.dispatch({type:’add’}, payload) action的type必写,调用dispatch,store会调用reducer,并把state和action传给reducer
- subscribe --监听state改变(订阅),返回一个函数,可用于取消监听
- reducer --纯函数,提供操作状态的各种方式,function reducer(state={}, action={}){},接受state,action返回新state
纯函数
- 在该函数中,没有任何副作用
- 该函数不依赖于外部的环境
- 不修改函数的输入值
- 相同的输入永远返回相同的输出,不能使用math.random或者请求数据
redux三大原则
- 单一数据源:整个应用的state被储存在一个object tree中,并且这个object tree只存在于唯一一个store中
- state是只读的:唯一改变的方法就是触发 action,action是一个用于描述已发生事件的普通对象
- 使用纯函数来执行修改state
react-redux使用
- 安装: npm i react-redux redux
- const store = createStore(reducer)
- 高阶组件,注入store数据源
- newCmp = connect(mapStatetoProps,mapDispatchToProps)(cmp)
- mapStatetoProps = (state)=>{return state}返回该组件需要的state
react-redux 提供的Hooks
- useStore()-获取store
- useSelector((state)=>{return state})-获取对应state
- useDispatch() -获取dispatch
redux-thunk
使action支持函数
- 如果action是对象,则直接调用reducer发起状态修改
- 如果action是函数,则执行该函数,并将getstate和dispatch传递给该函数,const store = createStore(reducer, applymiddleware(thunk,...多个))
- hooks时代可以使用自定义hooks替代中间件,方便简洁,具体就是:方法内获取收据,获取到数据后,再调用dispatch来修改数据
项目结构
App.js
index.js
static-静态资源(图片、css)
src
component-存放公共组件
view-视图层
components-页面级组件
index.js
index.module.css
store-状态仓库
action
reducer
index.js
router.js-路由表
package.json
webpack.config.js
其他
React.StrictMode
严格模式,即将废弃的语法都禁止使用,比如:废弃的will生命周期,refs获取dom等
index.module.css
支持css模块化,避免同名样式相互污染 :local(.local)局部变量 :globle(.public)全局,不进行混淆编译
按需加载处理
使用suspense和lazy进行懒加载设置 1.子组件用到再展示
<Suspense fallback={<div>模块加载中…</div>}>
<Child>
</Suspense>
2.可以应用于路由,用到路由再加载组件