react 交互

Microinteractions guide a user through your application. They reinforce your user experience and provide delight.

微交互引导用户完成您的应用程序。 它们可以增强您的用户体验并带来愉悦感。

You may have seen some of the slick examples of microinteractions on Dribble or CodePen. But do you know how to build your own library of similar UI widgets?

您可能已经看到了Dribble或CodePen上的一些微交互示例。 但是,您知道如何构建自己的类似UI小部件的库吗?

In this article, I’ll focus on animated microinteractions using React, Facebook’s popular, component-oriented UI framework. I’ll build three interactions for a searchbox:

在本文中,我将重点介绍使用Facebook流行的面向组件的UI框架React的动画微交互。 我将为搜索框构建三个交互:

  • open and close the text box打开和关闭文本框
  • move to the top of the screen移到屏幕顶部
  • shake (indicating an error)摇动(指示错误)

I’ll use a few different implementations:

我将使用一些不同的实现:

  • CSS transitions

    CSS过渡

  • react-motion

    React运动

  • react-animations

    React动画

Here’s a live demo and the code that powers it.

这是一个现场演示以及支持它的代码 。

This is one of several posts about Higher Order (HOC) and Stateless Functional Components. The first post is about code reuse in React and React Native, via these techniques.

这是有关高阶(HOC)和无状态功能组件的几篇文章之一。 第一篇文章是关于通过这些技术在React和React Native中的代码重用。

什么是微交互? (What is a Microinteraction?)

Dan Saffer (who wrote the book) gives us this definition: “Microinteractions are contained product moments that revolve around a single use case — they have one main task.”

Dan Saffer (写这本书的人)给了我们这样的定义 :“微交互包含围绕一个用例的产品时刻,它们具有一项主要任务。”

Examples might be clearer. Some microinteractions are everywhere, such as a cursor change when hovering over a link or the vibration of your phone when you switch to silent mode. Others, such as an item being added to a shopping cart, aren’t so common (yet).

例子可能更清楚。 到处都有一些微交互,例如,将鼠标悬停在链接上时会更改光标,或者切换到静音模式时手机会振动。 其他事物(例如,添加到购物车中的商品)并不普遍(尚未)。

我为什么要关心微交互? (Why should I care about Microinteractions?)

Microinteractions can provide feedback and make your application memorable. When users have so many app choices, better microinteractions might be the clichéd better mousetrap you should build.

微交互可以提供反馈并使您的应用程序令人难忘。 当用户有如此多的应用程序选择时,更好的微交互可能是您应该构建的老套的更好的捕鼠器。

But I am not a UX designer. So I suggest reading Nick Babich’s post about microinteractions.

但是我不是用户体验设计师。 因此,我建议阅读Nick Babich的有关微交互的文章 。

入门 (Getting Started)

I’ll use create-react-app to bootstrap a React application, but any React setup method will work. Also, I like Material-UI, so I’ll import that too. (This choice is arbitrary — you could use another widget library or manually style your elements.)

我将使用create-react-app引导React应用程序,但是任何React设置方法都可以使用。 另外,我喜欢Material-UI ,所以我也将其导入。 (此选择是任意的,您可以使用其他小部件库或手动设置元素样式。)

create-react-app search-box-animation
cd search-box-animation
npm install --save material-ui react-tap-event-plugin

组件:一个简单的搜索框 (The Component: a Simple Search Box)

I’ll create a simple search box. It will comprise two elements: a search icon button and a text box. I’ll create a stateless functional component for the search box. (Stateless functional components are functions that render React components and do not maintain state, i.e. use setState. You can learn more in this tutorial or my previous post.)

我将创建一个简单的搜索框。 它包含两个元素:一个搜索图标按钮和一个文本框。 我将为搜索框创建一个无状态的功能组件。 (无状态功能组件是呈现React组件并且不维护状态的函数,即使用setState 。您可以在本教程或我之前的文章中了解更多信息 。)

SearchBox.js

SearchBox.js

import React from 'react';
import {TextField, IconButton} from 'material-ui'
import SearchIcon from 'material-ui/svg-icons/action/search';
const SearchBox = ({isOpen, onClick}) => {const baseStyles = {open: {width: 300,},closed: {width: 0,},smallIcon: {width: 30,height: 30},icon: {width: 40,height: 40,padding: 5,top: 10},frame: {border: 'solid 1px black',borderRadius: 5}};
const textStyle = isOpen ? baseStyles.open : baseStyles.closed;
const divStyle = Object.assign({}, textStyle, baseStyles.frame);divStyle.width += baseStyles.icon.width + 5;
return (<div style={divStyle}><IconButton iconStyle={baseStyles.smallIcon} style={baseStyles.icon} onClick={() => onClick()}><SearchIcon /></IconButton><TextField name='search' style={textStyle}/></div>);
};
export  default SearchBox;

(I’ll use the onClick callback later.)

(稍后我将使用onClick回调。)

The isOpen prop sets the SearchBox open or closed rendering.

isOpen道具将SearchBox设置为打开或关闭渲染。

使用高阶分量来分离问题 (Using Higher Order Components to Separate Concerns)

I could change SearchBox to a regular component and add code that would open and close the text box when clicked, for example.

例如,我可以将SearchBox更改为常规组件,并添加代码,这些代码将在单击时打开和关闭文本框。

But I prefer to separate the animation from the core purpose of the search box. The search box shows/captures a query value and submits this query to some other controller. This is a subjective design decision, but it has practical benefits: I can reuse the microinteraction logic with another user input component.

但是我更喜欢将动画与搜索框的核心目的分开。 搜索框显示/捕获查询值,并将此查询提交给其他控制器。 这是一个主观的设计决定,但是它具有实际的好处:我可以将微交互逻辑与另一个用户输入组件一起重用。

Higher Order Components (HOC) are functions that return a new component. This component wraps a component(s) and adds functionality. I will create an HOC to add the open/close behavior to the SearchBox.

高阶组件 (HOC)是返回新组件的函数。 该组件包装组件并添加功能。 我将创建一个HOC来将打开/关闭行为添加到SearchBox

Create expanding-animation.js

创建expanding-animation.js

import React, {Component} from 'react';
const makeExpanding = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {isOpen: false};}onClick = () => {this.setState({isOpen: !this.state.isOpen});};render() {return (<Target {...this.props}isOpen={this.state.isOpen}onClick={this.onClick}/>);}}
};
export default makeExpanding;

Update App.js as follows:

如下更新App.js

import React, {Component} from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';// (Make material-ui happy)
// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();import SearchBox from './SearchBox'
import makeExpanding from './expanding-animation';const ExpandingSearchBox = makeExpanding(SearchBox);class App extends Component {render() {//https://css-tricks.com/quick-css-trick-how-to-center-an-object-exactly-in-the-center/const style = {position: 'fixed',top: '50%',left: '50%',transform: 'translate(-50%, -50%)',};return (<MuiThemeProvider><div style={style}><ExpandingSearchBox/></div></MuiThemeProvider>);}
}
export default App;

If you run npm start, you’ll have a search icon that you can click to open and close the text box.

如果您运行npm start ,则会有一个搜索图标,您可以单击该图标以打开和关闭文本框。

It works, but the opening and closing is jarring. An animation can smooth the effect.

它有效,但是打开和关闭很麻烦。 动画可以使效果平滑。

动画制作 (Animations)

There are three general approaches to animations.

动画有三种通用方法。

  1. CSS transitionsCSS过渡
  2. CSS animationsCSS动画
  3. rapid and repeated rendering of an element to simulate motion (manual key framing)快速重复渲染元素以模拟运动(手动关键帧)

CSS transitions change a property value (like width) over some time duration. The change doesn’t have to be linear; you can specify functions for changing the values.

CSS过渡会在一段时间内更改属性值(如width)。 变化不必是线性的。 您可以指定用于更改值的函数。

CSS animations change the style for an element (like size, color, and position). Each incremental style is a keyframe. You create a keyframe series to achieve a desired effect.

CSS动画会更改元素的样式(如大小,颜色和位置)。 每个增量样式都是一个关键帧。 您创建关键帧系列以实现所需的效果。

Both CSS tactics repeatedly render elements to simulate motion. You can do the calculations yourself, i.e. option (3). Several Javascript animation frameworks use this approach, managing the calculations. (I’ll use react-motion in a later example.)

两种CSS策略都反复渲染元素以模拟运动。 您可以自己进行计算,即选项(3)。 一些Javascript动画框架使用这种方法来管理计算。 (我将在后面的示例中使用react-motion。)

I will use all these techniques in the examples below, but I’ll start with CSS transitions.

我将在下面的示例中使用所有这些技术,但是我将从CSS过渡开始。

展开搜索框 (Expanding the Search Box)

The expanding text box animation needs one CSS property: transition

扩展的文本框动画需要一个CSS属性: transition

Change expanding-animation.js as follows,

如下更改expanding-animation.js

import React, {Component} from 'react';
const animationStyle = {transition: 'width 0.75s cubic-bezier(0.000, 0.795, 0.000, 1.000)'
};
const makeExpanding = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {isOpen: false};}onClick = () => {this.setState({isOpen: !this.state.isOpen});};render() {return (<Target {...this.props}isOpen={this.state.isOpen}onClick={this.onClick}additionalStyles={{text: animationStyle, frame: animationStyle}}/>);}}
};
export default makeExpanding;

Looking at the change in line 21, additionalStyles, SearchBox will merge this style with it’s existing styles in line 29 and 31 below. (I’ll return to the transition CSS property in line 2 in a moment.)

看着在第21行的变化, additionalStylesSearchBox将在第29行及以下31合并这种风格与它的现有样式。 (稍后我将在第2行中返回Transition CSS属性。)

Update SearchBox.js

更新SearchBox.js

import React from 'react';
import {TextField, IconButton} from 'material-ui'
import SearchIcon from 'material-ui/svg-icons/action/search';
const SearchBox = ({isOpen, onClick, additionalStyles}) => {const baseStyles = {open: {width: 300,},closed: {width: 0,},smallIcon: {width: 30,height: 30},icon: {width: 40,height: 40,padding: 5,top: 10},frame: {border: 'solid 1px black',borderRadius: 5}};let textStyle = isOpen ? baseStyles.open : baseStyles.closed;textStyle = Object.assign(textStyle, additionalStyles ? additionalStyles.text : {});const divStyle = Object.assign({}, textStyle, baseStyles.frame, additionalStyles ? additionalStyles.frame : {});divStyle.width += baseStyles.icon.width + 5;return (<div style={divStyle}><IconButton iconStyle={baseStyles.smallIcon} style={baseStyles.icon} onClick={() => onClick()}><SearchIcon /></IconButton><TextField name='search' style={textStyle}/></div>);
};
export  default SearchBox;

With the styles merged, the animation will take effect.

合并样式后,动画将生效。

The result is a smooth expansion of the text box width, giving the appearance it opens. The CSS transition property controls this (from line 2 in expanding-animation.js).

结果是文本框宽度的平滑扩展,使文本框具有打开的外观。 CSS transition属性对此进行控制(从expanding-animation.js第2行开始)。

transition: 'width 0.75s cubic-bezier(0.000, 0.795, 0.000, 1.000)'

I encourage you to read the documentation for the CSS transition property, as there are a variety of options. In the example, there are three parameters:

我建议您阅读CSS过渡属性的文档 ,因为有很多选择。 在示例中,有三个参数:

  1. property to change: width

    要更改的属性: width

  2. duration of transition: 0.75s

    过渡时间: 0.75s

  3. function to control timing: cubic-bezier(0.000, 0.795, 0.000, 1.000)’

    控制时序的功能: cubic-bezier(0.000, 0.795, 0.000, 1.000)'

While I chose cubic-bezier as the function, linear or ease are among other options. There are interactive tools that help you select these values, such as this cubic-bezier builder.

当我选择cubic-bezier作为函数时, linearease是其他选择。 有一些交互式工具可以帮助您选择这些值,例如: cubic-bezier builder 。

移动搜索框 (Moving the Search Box)

Check out the following concept animation I found on Dribble:

看看我在Dribble上发现的以下概念动画:

There are multiple elements in the interaction; but I’d like to focus on the movement of the search box to the top of the screen.

交互中包含多个元素; 但我想着重将搜索框移动到屏幕顶部。

I can move my humble search box with a CSS transition. Create a new HOC, move-up-animation.js

我可以通过CSS转换来移动不起眼的搜索框。 创建一个新的HOC, move-up-animation.js

import React, {Component} from 'react';
const animationStyle = {transform: 'translateY(-150px)',transition: 'transform 1s ease'
};
const makeMoveUp = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {moveTop: false};}onClick = () => {this.setState({moveTop: !this.state.moveTop});};render() {return (<Target isOpen={true}onClick={this.onClick}additionalStyles={{text: {}, frame: this.state.moveTop ? animationStyle : {}}}/>);}}
};
export default makeMoveUp;
view rawmove-up-animation.js hosted with ❤ by GitHub

This is like the makeExpanding HOC function, except does a translation (move up). Also, the animation style applies only to the outer frame (div).

就像makeExpanding HOC函数一样,只是进行翻译(向上移动)。 此外,动画样式仅适用于外框( div )。

Update App.js,

更新App.js

import React, {Component} from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';// (Make material-ui happy)
// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();import SearchBox from './SearchBox'
import makeMoveUp from './move-up-animation';
const MoveUpSearchBox = makeMoveUp(SearchBox);
class App extends Component {render() {//https://css-tricks.com/quick-css-trick-how-to-center-an-object-exactly-in-the-center/const style = {position: 'fixed',top: '50%',left: '50%',transform: 'translate(-50%, -50%)',};return (<MuiThemeProvider><div style={style}><MoveUpSearchBox/></div></MuiThemeProvider>);}
}
export default App;
view rawApp.js-2 hosted with ❤ by GitHub

and you should see

你应该看到

Perhaps you want a bouncy effect. You could use react-motion. It is a popular React library which uses spring dynamics to control animations. (A good introduction, by Nash Vail, is here.)

也许您想要有弹性的效果。 您可以使用react-motion 。 这是一个流行的React库,它使用弹簧动力学来控制动画。 ( Nash Vail的一个很好的介绍在这里 。)

npm install --save react-motion

Create spring-up-animation.js

创建spring-up-animation.js

import React, {Component} from 'react';
import {Motion, spring, presets} from 'react-motion'
const makeSpringUp = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {moveTop: false};}onClick = () => {this.setState({moveTop: !this.state.moveTop});};render() {const style = {translateY: this.state.moveTop ? spring(-150, presets.wobbly) : spring(0)};return (<Motion style={style}>{({translateY}) => (<Target isOpen={true}onClick={this.onClick}additionalStyles={{text: {},frame: {transform: `translateY(${translateY}px)`}}}/>)}</Motion>);}}
};
export default makeSpringUp;
view rawspring-up-animation.js hosted with ❤ by GitHub

As this isn’t a react-motion tutorial, I will briefly summarize how this works. React-motion wraps the animated component, Target, with its own component, Motion. (There are other react-motion components, such as TransitionMotion and Staggered Motion.)

由于这不是React运动教程,因此我将简要概述其工作原理。 React-motion将动画组件Target封装为其自己的Motion组件。 (还有其他React运动组件,例如TransitionMotionStaggered Motion 。)

React-motion interpolates, using spring dynamics, a series of interim values. It provides the values to the animated component as a style. This style determines the visual transition in the animation.

React运动使用弹簧动力学插值一系列中间值。 它将值作为样式提供给动画组件。 此样式确定动画中的视觉过渡。

The image below shows the result (with a wobbly spring to highlight the effect).

下图显示了结果(带有颤抖的弹簧以突出显示效果)。

You could use react-motion for a range of effects. For example, you could change the text box to expand like a spring.

您可以将react-motion用于多种效果。 例如,您可以更改文本框使其像弹簧一样展开。

(spring-up-animation.js and move-up-animation.js have the same onClick state logic, so I refactored the common parts. Details are here.)

( spring-up-animation.jsmove-up-animation.js具有相同的onClick状态逻辑,因此我重构了公共部分。详细信息在这里 。)

摇动搜索框 (Shaking the Search Box)

I want to provide feedback to the user about erroneous queries. You could use error messages, but I’d like to do something more whimsical: shake the search box.

我想向用户提供有关错误查询的反馈。 您可以使用错误消息,但我想做一些更怪异的操作:摇动搜索框。

I could use react-motion, but I’d like to look at another technique: keyframe animation.

我可以使用react-motion,但我想看看另一种技术:关键帧动画。

React-animations is a React library for keyframe animations. It injects CSS keyframes into a DOM style sheet. (The other examples have only used inline styles.)

React-animations是一个用于关键帧动画的React库。 它将CSS关键帧注入到DOM样式表中。 (其他示例仅使用内联样式。)

npm install --save react-animations

I also need a library, like Radium or Aphrodite, to handle the CSS style sheet injection. I’ve chosen Aphrodite, as I’ve used it before.

我还需要一个库,例如Radium或Aphrodite ,来处理CSS样式表注入。 我选择了Aphrodite,就像我之前使用过的一样。

npm install --save aphrodite

Create another HOC, shake-animation.js

创建另一个HOC, shake-animation.js

import React, {Component} from 'react';
import {headShake} from 'react-animations';
import {StyleSheet, css} from 'aphrodite';
const styles = StyleSheet.create({headShake: {animationName: headShake,animationDuration: '1s'}
});
const makeValidationErrorAnimation = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {shouldShake: false};}onClick = () => {this.setState({shouldShake: true}, () => {const self = this;setTimeout(() => self.setState({shouldShake: false}), 1000);});};render() {return (<Target isOpen={true}onClick={this.onClick}additionalStyles={{text: {}, frame: {}}}frameClass={this.state.shouldShake ? css(styles.headShake) : ''}/>);}}
};
export default makeValidationErrorAnimation;

There are a few key sections. Line 4 uses Aphrodite to create the style sheet for the react-animations effect, head-shake. Line 29 sets the CSS class for the animation on Target. (This requires a tweak to SearchBox to use the CSS class. Look at the use of frameClass in the source of SearchBox.js.) The onClick handler on line 17 is more complicated.

有几个关键部分。 第4行使用Aphrodite创建用于React动画效果的样式表head-shake 。 第29行在Target上设置动画CSS类。 (这需要对SearchBox进行调整才能使用CSS类。请在SearchBox.js的源代码中查看frameClass的用法。)第17行的onClick处理程序更加复杂。

重新启动动画 (Restarting an Animation)

I’d like to do the ‘head shake’ on each validation error (or whatever trigger is used). But since the animation is a CSS class, I can’t simply set the same class again; it would have no effect. This CSS Tricks post outlines a few options. The simplest is a timeout that removes the CSS animation class. When you add it again (for a new event), you’ll see the ‘head shake’.

我想对每个验证错误(或使用任何触发器)进行“摇头”操作。 但是由于动画是CSS类,所以我不能简单地再次设置相同的类。 它不会有任何效果。 此CSS技巧文章概述了一些选项。 最简单的方法是删除CSS动画类的超时。 再次添加(针对新事件)时,您会看到“摇头”。

放在一起:组成一个复杂的组件 (Putting It Together: Composing a Complex Component)

I’ve created several HOCs for different animations. But you can also chain the HOCs to create a compound component. It will open the text box when clicked and shake on erroneous input.

我为不同的动画创建了多个HOC。 但是,您也可以链接HOC以创建复合组件。 单击它会打开文本框,并摇晃错误的输入。

First, you’ll need to make a few changes toSearchBox

首先,您需要对SearchBox进行一些更改

import React from 'react';
import {TextField, IconButton} from 'material-ui'
import SearchIcon from 'material-ui/svg-icons/action/search';
const baseStyles = {open: {width: 300,},closed: {width: 0,},smallIcon: {width: 30,height: 30},icon: {width: 40,height: 40,padding: 5,top: 10},frame: {border: 'solid 1px black',borderRadius: 5}
};
const SearchBox = ({isOpen, query, onClick, onSubmit, onQueryUpdate, additionalStyles, frameClass}) => {const handleKeyDown = (event) => {const ENTER_KEY = 13;if (event.keyCode === ENTER_KEY) {event.preventDefault();onSubmit();}};let textStyle = isOpen ? baseStyles.open : baseStyles.closed;textStyle = Object.assign(textStyle, additionalStyles ? additionalStyles.text : {});const divStyle = Object.assign({}, textStyle, baseStyles.frame, additionalStyles ? additionalStyles.frame : {});divStyle.width += baseStyles.icon.width + 5;return (<div style={divStyle} className={frameClass ? frameClass : ''}><IconButton iconStyle={baseStyles.smallIcon} style={baseStyles.icon} onClick={() => onClick()}><SearchIcon /></IconButton><TextField name='search'style={textStyle}value={query}onKeyDown={handleKeyDown}onChange={(event, value) => onQueryUpdate(value)}/></div>);
};
export  default SearchBox;

SearchBox is now a controlled component (fancy term for using React to manage the text box’s input value). It also provides a callback, onSubmit, for submitting the search query (when a user presses the Enter key).

SearchBox现在是一个受控组件 (使用React使用该术语来管理文本框的输入值)。 它还提供了一个回调onSubmit ,用于提交搜索查询(当用户按下Enter键时)。

You also need to change shake-animation.js. Clicking the search icon should not cause the shake. Instead, I want another component to determine when to ‘shake’. This separates the validation logic from code that controls the animation.

您还需要更改shake-animation.js 。 单击搜索图标不应引起抖动。 相反,我希望另一个组件来确定何时“摇动”。 这将验证逻辑与控制动画的代码分开。

startShake is a flag to reset the animation. But this is an implementation detail. It should be encapsulated, as internal state, in the makeShakeAnimation HOC.

startShake是用于重置动画的标志。 但这是一个实现细节。 应该将其作为内部状态封装在makeShakeAnimation HOC中。

import React, {Component} from 'react';
import {headShake} from 'react-animations';
import {StyleSheet, css} from 'aphrodite';
const styles = StyleSheet.create({headShake: {animationName: headShake,animationDuration: '1s'}
});
const makeShakeAnimation = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {startShake: props.shouldShake};}componentWillReceiveProps(nextProps) {this.setState({startShake: nextProps.shouldShake}, () => {const self = this;setTimeout(() => self.setState({startShake: false}), 1000);});//https://css-tricks.com/restart-css-animation/ for discussion on restart}render() {return (<Target {...this.props}frameClass={this.state.startShake ? css(styles.headShake) : ''}/>);}}
};
export default makeShakeAnimation;

startShake is dependent on shouldShake. I can use componentWillReceiveProps to respond to prop changes. (It’s parent, the validation component, provides these props.) So I moved the previous onClick logic to componentWillReceiveProps.

startShake取决于shouldShake 。 我可以使用componentWillReceiveProps来响应道具更改。 (它的父级(验证组件)提供了这些道具。)因此,我将先前的onClick逻辑移至componentWillReceiveProps

The change in line 27, {...this.props}, passes all props to the wrapped component, Target. (I need to similarly change the render method in expanding-animation.js. The details are here.)

第27行的更改{...this.props}将所有props传递给包装的组件Target 。 (我需要类似地更改expanding-animation.jsrender方法。详细信息在这里 。)

I can now add a component that will control when to shake.

现在,我可以添加一个控件来控制何时摇动。

Create search-box-controller.js

创建search-box-controller.js

import React, {Component} from 'react';import makeExpanding from './expanding-animation';
import makeShakingAnimation from './shake-animation';const makeAnimatedValidationSearchBox = (Target) => {const WrappedComponent = makeShakingAnimation(makeExpanding(Target));return class extends Component {constructor(props) {super(props);this.state = {query: '', hasError: false};}onQueryUpdate = (value) => {this.setState({query: value, hasError:false});};onSubmit = () => {this.setState({hasError: true});};render() {return (<WrappedComponentonQueryUpdate={this.onQueryUpdate}query={this.state.query}onSubmit={this.onSubmit}shouldShake={this.state.hasError}/>);}}
};export default makeAnimatedValidationSearchBox;

This is another HOC. It does not have visual elements, but it controls the logical behavior of the wrapped component. (Dan Abramov has a good post explaining such separation.) In this case, all queries as erroneous, but in a real application, I’d validate queries and connect to APIs.

这是另一个HOC。 它没有视觉元素,但是它控制了包装组件的逻辑行为。 ( Dan Abramov有一篇很好的文章解释了这种分离。)在这种情况下,所有查询都是错误的,但是在实际应用程序中,我将验证查询并连接到API。

Lastly, I want to highlight that makeAnimatedValidationSearchBox is an HOC that chains two other HOCs.

最后,我想强调一下, makeAnimatedValidationSearchBox是一个链接其他两个HOC的HOC。

const WrappedComponent =makeShakingAnimation(makeExpanding(Target));

Another small update toApp.js

App.js另一个小更新

import React, {Component} from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';// (Make material-ui happy)
// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
import SearchBox from './SearchBox'import makeAnimatedValidationSearchBox from './search-box-controller';
const AnimatedSearchBox = makeAnimatedValidationSearchBox(SearchBox);class App extends Component {render() {//https://css-tricks.com/quick-css-trick-how-to-center-an-object-exactly-in-the-center/const style = {position: 'fixed',top: '50%',left: '50%',transform: 'translate(-50%, -50%)',};return (<MuiThemeProvider><div style={style}><AnimatedSearchBox/></div></MuiThemeProvider>);}
}
export default App;

(Line 12 uses the new HOC)

(第12行使用新的HOC)

and execute run npm start

并执行run npm start

I’ve created a compound component that uses multiple microinteractions. They are reusable and discrete.

我创建了使用多个微交互的复合组件。 它们是可重用和离散的。

结语 (Wrapping Up)

I’ve sampled each of the approaches: CSS transitions, react-motion and react-animations. I wish you could pick one approach, but it’s hard to contort a single approach for all use cases. Thankfully, you can mix-and-match libraries and techniques. And you can encapsulate the details in reusable HOCs.

我已经对每种方法进行了采样:CSS过渡,react-motion和react-animations。 我希望您可以选择一种方法,但是很难针对所有用例扭曲一种方法。 值得庆幸的是,您可以混合和匹配库和技术。 您可以将细节封装在可重用的HOC中。

You might want to check out libraries such recompose, that make HOC creation easier.

您可能想检出诸如recompose之类的库,这些库使HOC的创建更加容易。

The GitHub repo for this project is here.

这个项目的GitHub仓库在这里 。

Please ♡ this post and follow me for future stories. Thanks for reading.

请♡这篇文章,并跟随我的未来故事。 谢谢阅读。

翻译自: https://www.freecodecamp.org/news/how-to-build-animated-microinteractions-in-react-aab1cb9fe7c8/

react 交互

react 交互_如何在React中建立动画微交互相关推荐

  1. django 传递中文_如何在Django中建立消息传递状态

    django 传递中文 by Ogundipe Samuel 由Ogundipe Samuel 如何在Django中建立消息传递状态 (How to Build a Message Delivery ...

  2. react 交互_如何在React应用程序中跟踪用户交互

    react 交互 by Faouzi Oudouh 通过Faouzi Oudouh 如何在React应用程序中跟踪用户交互 (How to track user interactions in you ...

  3. react网格生成_如何在React中构建实时可编辑数据网格

    react网格生成 by Peter Mbanugo 彼得·姆巴努戈(Peter Mbanugo) 如何在React中构建实时可编辑数据网格 (How to Build a Real-time Edi ...

  4. python 线性回归模型_如何在Python中建立和训练线性和逻辑回归ML模型

    python 线性回归模型 Linear regression and logistic regression are two of the most popular machine learning ...

  5. oracle mysql 透明网关_如何在Oracle中建立透明网关

    展开全部 当在Oracle 环境下通过透明网关建立一个对SQL Server 的连接时,要用到如下的语句,Create database link test connect to user ident ...

  6. wordpress标签云_如何在WordPress中建立更好的标签云

    wordpress标签云 Once you've defined a great set of tags for your WordPress posts (or pages), you'll wan ...

  7. css 动画使用_如何在CSS中使用动画

    css 动画使用 使用CSS动画 (Using CSS Animations) CSS animations add beauty to the webpages and make transitio ...

  8. figma设计_如何在Figma中构建设计入门套件(第1部分)

    figma设计 Figma教程 (Figma Tutorial) Do you like staring at a blank canvas every time you start a new pr ...

  9. python中如何画logistic_如何在 Python 中建立和训练线性和 logistic 回归 ML 模型?

    原标题:如何在 Python 中建立和训练线性和 logistic 回归 ML 模型? 英语原文: 翻译:(Key.君思) 线性回归与logistic回归,是. 在我的里,你们已经学习了线性回归机器学 ...

最新文章

  1. CDN百科第七期 | 关于CDN的原理、术语和应用场景那些事
  2. linux新建用户代码,Linux_用dsadd添加用户的代码,描述: 此工具命令将一些具体 - phpStudy...
  3. 刻录光盘(信息学奥赛一本通-T1383)
  4. 终结者:具体解释Nginx(一)
  5. Tomcat是如何将请求一步步传递到我们编写的HttpServlet类中的
  6. [leetCode]Merge k Sorted Lists
  7. 电子签章助力水电气公共事业服务“一网通办”
  8. android 计时器函数,Android Chronometer控件实现计时器函数详解
  9. idea一顿切换分之后编译项目提示找不到其他分支类的解决办法~
  10. 如何在 ggplot2 中制作饼图(附示例)
  11. APP地推效果监测精准方案
  12. ElasticSearch聚合分析API
  13. linux下利用dnw烧写文件,dnw安装与配置
  14. Advantech PCI card 驱动注册 --W T
  15. 管道,Linux命令,Windows命令,cmd命令,tmux,vim,shell,bash,sh文件,bat文件
  16. Swift - 判等
  17. 以实验理解交换机原理
  18. ADO数据库连接中的Integrated Security和Persist Security Info参数的作用
  19. 随心所“语”之 3B大战:robots协议问题
  20. 关于使用U盘安装ESXi发生的一些错误及解决经验

热门文章

  1. idea中HTML可以打debug吗,Intellij IDEA中使用Debug调试
  2. php函数网,php函数
  3. java实现矩阵相乘
  4. shell:多个文件按行合并
  5. 1,滑动验证,前后台接口
  6. 有一句说一千句,是作家....
  7. 基于leveldb,levigo做二次开发
  8. neroLinux3.x的序列号
  9. 类的转换函数调用的优先级与是否用const修饰的关系
  10. Mysql-my-innodb-heavy-4G.cnf配置文件注解