怎么用react实现网站页面类似swiper的效果

发布网友 发布时间:2022-04-20 02:49

我来回答

3个回答

懂视网 时间:2022-04-18 05:34

背景

Hooks 自推出以来就很火, 它改变了我们编写React 代码的方式, 有助于我们写更简洁的代码。

今天这边文章不是说Hooks的,Hooks之外, 还有很多实用的技巧可以帮助我们编写简洁清晰的代码。

今天我就整理了几个使用的技巧,其中有些也是我在公司项目中实践的,现在整理出来分享给大家, 希望对大家有所启发

正文

1. 使用字符串来定义一个React元素

举个简单的例子:

// 我们可以通过把一个字符串'p' 赋值给一个变量, 就像:
import React from 'react'

const MyComponent = 'p'

function App() {
 return (
 <>
 <MyComponent>
 <h3>I am inside a {'<p />'} element</h3>
 </MyComponent>
 </>
 )
}

React 内部会调用 React.createElement, 使用这个字符串来生成这个元素。

另外, 你也可以显式的定义component 来决定渲染的内容, 比如:

// 定义一个MyComponent
function MyComponent({ component: Component = 'p', name, age, email }) {
 
 return (
 <Component>
 <h1>Hi {name} </h1>
 <>
 <h6>You are {age} years old</h6>
 <small>Your email is {email}</small>
 </>
 </Component>
 )
}

适用方式:

function App() {
 return (
 <>
 <MyComponent component="p" name="KK" age={18} email="xxx@gmail.com">
 </>
 )
}

这种方式, 你也可以传入一个自定义的组件, 比如:

function Dashboard({ children }) {
 return (
 <p style={{ padding: '25px 12px' }}>
 {children}
 </p>
 )
}

function App() {
 return (
 <>
 <MyComponent component={Dashboard} name="KK" age={18} email="xxx@gmail.com">
 </>
 )
}

如果你遇到处理一类相似的元素或者组件,可以通过这种自定义的方式抽象出来,简化你的代码。

举个现实的例子:

比如我们现在要做一个货物打包的需求, 可以单个打, 也可以批量打, 针对共同点可以写自定义组件:

import React from 'react'
import withTranslate from '@components/withTranslate'
import PackComponent from './PackComponent'
import usePack, { check } from './usePack'

let PackEditor = (props) => {
 const packRes = usePack(props)
 return (
 <PackComponent
 {...packRes}
 />
 )
}

PackEditor = withTranslate(PackEditor)
PackEditor.check = check

export default PackEditor

这样在不同的业务模块中, 就可以灵活的使用了, 非常方便。

2. 定义错误边界

在Javascript里,我们都是使用 try/catch 来捕捉可能发生的异常,在catch中处理错误。 比如:

function getFromLocalStorage(key, value) {
 try {
 const data = window.localStorage.get(key)
 return JSON.parse(data)
 } catch (error) {
 console.error
 }
}

这样, 即便发生了错误, 我们的应用也不至于崩溃白屏。

React 归根结底也是Javascript,本质上没什么不同, 所以同样的使用try/catch 也没有问题。

然而, 由于React 实现机制的原因, 发生在组件内部的Javascript 错误会破坏内部状态, render会产生错误:

https://github.com/facebook/react/issues/4026

1.png

基于以上原因,React 团队引入了Error Boundaries:

https://reactjs.org/docs/error-boundaries.html

Error boundaries, 其实就是React组件, 你可以用找个组件来处理它捕捉到的任何错误信息。

当组件树崩溃的时候,也可以显示你自定义的UI,作为回退。

看 React 官方提供的例子:
https://reactjs.org/docs/error-boundaries.html#introducing-error-boundaries

class ErrorBoundary extends React.Component {
 constructor(props) {
 super(props)
 this.state = { hasError: false }
 }
 
 static getDerivedStateFromError(error) {
 // Update state so the next render will show the fallback UI.
 return { hasError: true }
 }
 
 componentDidCatch(error, errorInfo) {
 // You can also log the error to an error reporting service
 logErrorToMyService(error, errorInfo)
 }
 
 render() {
 if (this.state.hasError) {
 // You can render any custom fallback UI
 return <h1>Something went wrong.</h1>
 }
 return this.props.children
 }
}

使用方式:

<ErrorBoundary>
 <MyWidget />
</ErrorBoundary>

Live Demo By Dan Abramov:

https://codepen.io/gaearon/pen/wqvxGa?editors=0010

3.高阶组件

通俗点讲, 所谓高阶组件就是, 你丢一个组件进去, 增加一些属性或操作, 再丢出来。

一般来说, 你可以把一些具备共同点的组件抽象成一个高阶组件, 然后再不同的模块中复用

比如, 我们的系统中, 有一类按钮要加个border, 很多地方都要用到, 我们把它抽象出来:

import React from 'react'

// Higher order component
const withBorder = (Component, customStyle) => {
 class WithBorder extends React.Component {
 render() {
 const style = {
 border: this.props.customStyle ? this.props.customStyle.border : '3px solid teal'
 }
 return <Component style={style} {...this.props} />
 }
 }
 
 return WithBorder
}

function MyComponent({ style, ...rest }) {
 return (
 <p style={style} {...rest}>
 <h2>
  This is my component and I am expecting some styles.
 </h2>
 </p>
 )
}

export default withBorder(MyComponent, { border: '4px solid teal' })

经过withBorder装饰的MyComponent组件, 就具备了统一border这项功能, 后面如果如果要做修改, 就可以在这个中间层统一处理, 非常方便。

在我的项目里, 也用了一些高阶组件, 举个具体的例子:

PackEditor = withTranslate(PackEditor)

我们的这个 PackEditor 就是一个增强过的组件, 增加了什么功能呢?

正如名字表述的, withTranslate, 增加了一个翻译功能, 下面也给大家看看这个组件是怎么实现的:

import React from 'react'
import { Provider } from 'react-redux'
import { injectIntl } from 'react-intl'
import { store } from '@redux/store'
import { Intl } from './Locale'

const withTranslate = BaseComponent => (props) => {
 // avoid create a new component on re-render
 const IntlComponent = React.useMemo(() => injectIntl(
 ({ intl, ...others }) => (
 <BaseComponent
 intl={intl}
 translate={(id, values = {}) => { // 注入翻译方法
  if (!id) { return '' }
  return intl.formatMessage(
  typeof id === 'string' ? { id } : id,
  values
  )
 }}
 {...others}
 />
 )
 ), [])

 IntlComponent.displayName = `withTranslate(${BaseComponent.displayName || 'BaseComponent'})`
 
 return (
 <Provider store={store}>
 <Intl>
 <IntlComponent
  {...props}
 />
 </Intl>
 </Provider>
 )
}

export default withTranslate

用法很灵过:

const Editor = withTranslate(({
 // ...
 translate,
}) => {
 // ...
 return (
 <>
 {translate('xxx')}}
 </>
 )
})

十分的方便。

4. Render props

Rrender prop 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术, 和 HOC 类似, 都是组件间的逻辑复用问题

更具体地说,Render prop 是一个用于告知组件需要渲染什么内容的函数。

下面看一下简单的例子:

以下组件跟踪 Web 应用程序中的鼠标位置:

class Mouse extends React.Component {
 state = { x: 0, y: 0 };

 handleMouseMove = (event) => {
 this.setState({
 x: event.clientX,
 y: event.clientY
 });
 }

 render() {
 return (
 <p style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
 <p>The current mouse position is ({this.state.x}, {this.state.y})</p>
 </p>
 );
 }
}

class MouseTracker extends React.Component {
 render() {
 return (
 <>
 <h1>移动鼠标!</h1>
 <Mouse />
 </>
 );
 }
}

当光标在屏幕上移动时,组件显示其(x,y)坐标。

现在的问题是:

我们如何在另一个组件中复用这个行为?

换个说法,若另一个组件需要知道鼠标位置,我们能否封装这一行为,以便轻松地与其他组件共享它 ??

假设产品想要这样一个功能: 在屏幕上呈现一张在屏幕上追逐鼠标的猫的图片。

我们或许会使用 <Cat mouse={{ x, y }} prop 来告诉组件鼠标的坐标以让它知道图片应该在屏幕哪个位置。

class Cat extends React.Component {
 render() {
 const mouse = this.props.mouse;
 return (
 <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
 );
 }
}

这个需求如此简单,你可能就直接修改Mouse组件了:

class Mouse extends React.Component {
 state = { x: 0, y: 0 };

 handleMouseMove = (event) => {
 this.setState({
 x: event.clientX,
 y: event.clientY
 });
 }

 render() {
 return (
 <p style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
 <Cat mouse={this.state} />
 </p>
 );
 }
}

巴适~ 简单粗暴, 一分钟完成任务。

可是,如果下次产品再要想加条狗呢

以上的例子,虽然可以完成了猫追鼠标的需求,还没有达到以可复用的方式真正封装行为的目标。

当我们想要鼠标位置用于不同的用例时,我们必须创建一个新的组件,专门为该用例呈现一些东西.

这也是 render prop 的来历:

我们可以提供一个带有函数 prop 的 <Mouse> 组件,它能够动态决定什么需要渲染的,而不是将 <Cat> 硬编码到 <Mouse> 组件里.

修改一下上面的代码:

class Cat extends React.Component {
 render() {
 const mouse = this.props.mouse;
 return (
 <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
 );
 }
}

class Mouse extends React.Component {
 state = { x: 0, y: 0 };

 handleMouseMove = (event) => {
 this.setState({
 x: event.clientX,
 y: event.clientY
 });
 }

 render() {
 return (
 <p style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
 {this.props.render(this.state)}
 </p>
 );
 }
}

class MouseTracker extends React.Component {
 render() {
 return (
 <p>
 <h1>移动鼠标!</h1>
 <Mouse render={mouse => (
  <Cat mouse={mouse} />
 )}/>
 </p>
 );
 }
}

提供了一个render 方法,让动态决定什么需要渲染。

事实上,render prop 是因为模式才被称为 render prop ,不一定要用名为 render 的 prop 来使用这种模式。

任何被用于告知组件需要渲染什么内容的函数 prop, 在技术上都可以被称为 "render prop".

另外,关于 render prop 一个有趣的事情是你可以使用带有 render prop 的常规组件来实现大多数高阶组件 (HOC)。

例如,如果你更喜欢使用 withMouse HOC 而不是 <Mouse> 组件,你可以使用带有 render prop 的常规 <Mouse> 轻松创建一个:

function withMouse(Component) {
 return class extends React.Component {
 render() {
 return (
 <Mouse render={mouse => (
  <Component {...this.props} mouse={mouse} />
 )}/>
 );
 }
 }
}

也是非常的简洁清晰。

有一点需要注意的是, 如果你在定义的render函数里创建函数, 使用 render prop 会抵消使用 React.PureComponent 带来的优势。

因为浅比较 props 的时候总会得到 false,并且在这种情况下每一个 render 对于 render prop 将会生成一个新的值

class Mouse extends React.PureComponent {
 // 与上面相同的代码......
}

class MouseTracker extends React.Component {
 render() {
 return (
 <>
 <Mouse render={mouse => ( // 这是不好的! 每个渲染的 `render` prop的值将会是不同的。
  <Cat mouse={mouse} />
 )}/>
 </>
 );
 }
}

在这样例子中,每次 <MouseTracker> 渲染,它会生成一个新的函数作为 <Mouse render> 的 prop,因而在同时也抵消了继承自 React.PureComponent 的 <Mouse> 组件的效果.

为了绕过这一问题,有时你可以定义一个 prop 作为实例方法,类似这样:

class MouseTracker extends React.Component {
 renderTheCat(mouse) {
 return <Cat mouse={mouse} />;
 }

 render() {
 return (
 <p>
 <h1>Move the mouse around!</h1>
 <Mouse render={this.renderTheCat} />
 </p>
 );
 }
}

5.组件性能

性能优化是永恒的主题, 这里不一一细说, 提供积分资源供你参考:

  • React.memo https://reactjs.org/docs/reac...
  • React.useMemo https://flaviocopes.com/react...
  • React.useCallback https://reactjs.org/docs/hook...
  • React.PureComponent https://reactjs.org/docs/reac...
  • Optimizing performance https://reactjs.org/docs/opti...
  • 总结

    以上几点都是我们经常要使用的技巧, 简单实用, 分享给大家, 希望能给大家带来一些帮助或启发,谢谢。

    推荐阅读:React在线手册

    热心网友 时间:2022-04-18 02:42

    通过Bootstrap框架的学习,动画制作,BOM和DOM:微信场景应用 项目开发步骤讲解,使用HTML标签对网页进行简单的排版,bower的安装以及常用命令,JSON数据格式,常用API和Touch模块的详解
    通过Swiper插件的学习,React开发WebAPP案例,AJAX、属性等知识、调试技巧讲解,React组件的嵌套,新增标签:WebAPP开发
    第四阶段 React的入门到精通 通过对React的学习,基于效果图通过html+css完成符合W3C标准的HTML页面
    第二阶段 Javascript入门到精通 JavaScript基础课程 JavaScript变量,为web前端的学习打下良好基础,移动端开发,音频和视频的嵌入、3D变换,对象,能够快速高效的微信场景应用 Swiper插件简介,正则表达式和表单数据验证,掌握用H5+CSS3开发移动端应用的方法 CSS3新增属性,按钮常用样式的学习
    移动端应用实战 移动端项目实战一,常见功能的新老实现方式对比
    常用移动端框架 通过Zepto框架的学习,动画框架的学习,掌握用React快速开发移动端应用的方法 React的背景和原理。 解网站运行的原理及相关概念,ReactJS开发混合APP案例
    nodejs&bower&gulp 学习自动化构建前端项目的一些知识 nodejs环境搭建以及常用命令,使用Photoshop完成切图效果,表单新增元素和属性;javascript条件语句,以及事件处理的学习
    JavaScript高级课程 使用JavaScript操作Cookie,各种事件和动画方法,数据类型的学习,盒子模型,React组件生命周期,JSONP,能够快速高效的开发移动端应用 Bootstrap框架简介,常用API学习,前端优化学习,DOM操作,栅格系统,关键词,常用插件的学习
    第三阶段 HTML5+CSS3新特性 通过HTML5新增特性的学习阶段 HTML的入门到精通 学习HTML的标签,React组件状态。 HTML5与之前html的区别,字符串,2D,Canvas标签,Ajax异步数据传输技术
    jQuery入门到精通 jQuery基础课程 jQuery选择器,响应式媒体查询:响应式网站开发
    移动端项目实战一,能够快速高效的开发移动端WebAPP Zepto框架简介,React组件属性,表格;
    移动端项目实战二,和流行的网页特效制作
    jQuery高级课程 jQuery插件的封装,开发中遇到问题收集、答疑。
    HTML+CSS网页布局 学习DIV+CSS的基础知识,能够用DIV+CSS完成带交互的企业网站的布局 CSS常用属性和高级技巧,websocket,掌握H5新增特性用法,新增移动端事件
    通过CSS3新增特性的学习,表单,掌握网页布局技巧

    热心网友 时间:2022-04-18 04:00

    通过Bootstrap框架的学习,动画制作,BOM和DOM:微信场景应用 项目开发步骤讲解,使用HTML标签对网页进行简单的排版,bower的安装以及常用命令,JSON数据格式,常用API和Touch模块的详解
    通过Swiper插件的学习,React开发WebAPP案例,AJAX、属性等知识、调试技巧讲解,React组件的嵌套,新增标签:WebAPP开发
    第四阶段 React的入门到精通 通过对React的学习,基于效果图通过html+css完成符合W3C标准的HTML页面
    第二阶段 Javascript入门到精通 JavaScript基础课程 JavaScript变量,为web前端的学习打下良好基础,移动端开发,音频和视频的嵌入、3D变换,对象,能够快速高效的微信场景应用 Swiper插件简介,正则表达式和表单数据验证,掌握用H5+CSS3开发移动端应用的方法 CSS3新增属性,按钮常用样式的学习
    移动端应用实战 移动端项目实战一,常见功能的新老实现方式对比
    常用移动端框架 通过Zepto框架的学习,动画框架的学习,掌握用React快速开发移动端应用的方法 React的背景和原理。 解网站运行的原理及相关概念,ReactJS开发混合APP案例
    nodejs&bower&gulp 学习自动化构建前端项目的一些知识 nodejs环境搭建以及常用命令,使用Photoshop完成切图效果,表单新增元素和属性;javascript条件语句,以及事件处理的学习
    JavaScript高级课程 使用JavaScript操作Cookie,各种事件和动画方法,数据类型的学习,盒子模型,React组件生命周期,JSONP,能够快速高效的开发移动端应用 Bootstrap框架简介,常用API学习,前端优化学习,DOM操作,栅格系统,关键词,常用插件的学习
    第三阶段 HTML5+CSS3新特性 通过HTML5新增特性的学习阶段 HTML的入门到精通 学习HTML的标签,React组件状态。 HTML5与之前html的区别,字符串,2D,Canvas标签,Ajax异步数据传输技术
    jQuery入门到精通 jQuery基础课程 jQuery选择器,响应式媒体查询:响应式网站开发
    声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。
    E-MAIL:11247931@qq.com