react 交互_如何在React中建立動畫微交互

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

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 transitions

    CSS過渡
  2. CSS animations

    CSS動畫
  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過渡開始。

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 。

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狀態邏輯,因此我重構了公共部分。詳細信息在這里 。)

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 交互

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/395735.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395735.shtml
英文地址,請注明出處:http://en.pswp.cn/news/395735.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HTTPS與MITM

HTTPS:基于SSL/TSL的HTTP協議 MITM:Man-In-The-Middle中間人攻擊 Https下中間人攻擊的思路&#xff1a; 1 去https化 2 向CA申請相似域名的證書 防范&#xff1a; 睜大雙眼轉載于:https://www.cnblogs.com/the-owl/p/5596254.html

PCB genesis自制孔點 Font字體實現方法

一.先看genesis原有Font字體 在PCB工程CAM加孔點字體要求時,通常我們直接用Geneis軟件給我們提供了2種孔點字體canned_57與canned_67,但此字體可能不能滿足各個工廠個性化需求&#xff0c;比如&#xff1a;孔密度&#xff0c;孔間距&#xff0c;孔形狀分布&#xff0c;如果有一…

Google 最新的 Fuchsia OS【科技訊息摘要】

轉自&#xff1a;http://www.cnblogs.com/pied/p/5771782.html 就是看到篇報道&#xff0c;有點好奇&#xff0c;就去FQ挖了點東西回來。 我似乎已開始就抓到了重點&#xff0c;沒錯&#xff0c;就是 LK 。 LK 是 Travis Geiselbrecht 寫的一個針對 ARM 的嵌入式操作系統&#…

java 03_Java基礎03—流程控制

流程控制參考資料&#xff1a;《Java從入門到精通》/明日科技編著. 4版. 北京&#xff1a;清華大學出版社&#xff0c;2016一、復合語句Java的復合語句由“{”開始&#xff0c;“}”結束&#xff0c;又稱為塊語句。復合語句都是由上至下被執行&#xff1b;復合語句中可以嵌套復…

這三種策略可以幫助女性在科技領域蓬勃發展

by Shubhi Asthana通過Shubhi Asthana 這三種策略可以幫助女性在科技領域蓬勃發展 (These 3 strategies can help women thrive in tech) As someone early on in her career, I’ve attended a few tech talks, conferences, and meetups. One thing I noticed is not many w…

手機衛士09_應用程序四種查看_ListView小標題_進程管理

手機衛士09_應用程序四種查看_ListView小標題_進程管理 1.懸浮窗體的功能實現: 1.1.應用程序的卸載: 包安裝器 packageInstall,包卸載packageruninstall intent.setData(Uri.pare(“package:” 應用程序包名)) 卸載完之后記得更新list集合,更新適配器. 但是不確定用戶是否點了…

pandas:根據行間差值進行數據合并

1. 問題描述 在處理用戶上網數據時&#xff0c;用戶的上網行為數據之間存在時間間隔&#xff0c;按照實際情況&#xff0c;若時間間隔小于閾值&#xff08;next_access_time_app&#xff09;&#xff0c;則可把這幾條上網行為合并為一條行為數據&#xff1b;若時間間隔大于閾值…

Flask學習 一 基本結構

-from flask import Flaskfrom flask import Flask,render_template-from flask import request-from flask import make_response-from flask import abort-from flask import redirect-# __name__參數決定程序的根目錄app Flask (__name__)-# app.route (/)-# def hello_wor…

java8的路徑_什么是路徑?

# 什么是路徑&#xff1f;文件系統以某種形式的媒體(通常為一個或多個硬盤驅動器)存儲和組織文件&#xff0c;使得它們可以容易地被檢索。目前使用的大多數文件系統將文件存儲在樹形(或分層)結構中。在樹的頂部是一個(或多個)根節點。在根節點下&#xff0c;有文件和目錄(Micro…

為什么toString方法可以用來區分數組和對象?

首先大家都應該知道在javascript中只有是對象都存在toString方法&#xff0c;將調用該方法的值轉換為字符串返回&#xff0c;如下&#xff1a; var arr [1, 2, 3];console.log(arr.toString()); //1,2,3 但對象的toString方法和其他優點不同&#xff0c;其返回的是類似 [objec…

平安 開源 數據庫 實踐_刻意的實踐-成為開源

平安 開源 數據庫 實踐by Anthony Ng由Anthony Ng 刻意的實踐-成為開源 (Deliberate Practice — Becoming an Open Sourcerer) I recently finished reading Cal Newport’s book, So Good They Can’t Ignore You. It’s a quick read, and it introduced me to the concept…

更新Composer依賴報錯處理Fatal error: Declaration of Fxp\Composer\AssetPlugin\Repository\AbstractAssetsRe...

更新Composer依賴報錯處理 Fatal error: Declaration of Fxp\Composer\AssetPlugin\Repository\AbstractAssetsRepository::search() must be compatible with Composer\Repository\RepositoryInterface::search($query, $mode 0, $type NULL) in C:\Users\Arthur\AppData\Ro…

解析su,su -,sudo的區別

2019獨角獸企業重金招聘Python工程師標準>>> 本人以前一直習慣直接使用root&#xff0c;很少使用su&#xff0c;前幾天才發現su與su -命令是有著本質區別的&#xff01; 大部分Linux發行版的默認賬戶是普通用戶&#xff0c;而更改系統文件或者執行某些命令&#xff…

java 前置通知_spring aop中的前置通知

fixassetServicemyInterceptormyInterceptor2在上面的配置文件中 我配置了兩個interceptor &#xff0c;這兩個interceptor的invoke方法中的邏輯是一樣的。public Object invoke(MethodInvocation invo) throws Throwable {//自己的橫切邏輯log....invo.proceed()}我想請教的問…

Java并發編程藝術讀書筆記

1、多線程在CPU切換過程中&#xff0c;由于需要保存線程之前狀態和加載新線程狀態&#xff0c;成為上下文切換&#xff0c;上下文切換會造成消耗系統內存。所以&#xff0c;可合理控制線程數量。 如何控制&#xff1a; &#xff08;1&#xff09;使用ps -ef|grep appname&#…

您可能不需要翻譯您JavaScript

by Alex Ewerlf由AlexEwerlf 您可能不需要翻譯您JavaScript (You might not need to transpile your JavaScript) Popular guides like YouMightNotNeedJQuery.com and You Don’t Need Lodash/Underscore have challenged common industry practices.諸如YouMightNotNeedJQue…

java maven 操作 收集的一些命令

maven打包&#xff1a; mvn clean package -Dmaven.test.skiptrue 運行jar: java -jar target/spring-boot-scheduler-1.0.0.jar 這種方式關掉控制臺就不可以訪問&#xff0c;現在要后臺運行的方式啟動 nohup java -jar target/spring-boot-scheduler-1.0.0.jar & 清理并…

手機h5 java平臺_H5 手機 App 開發入門:技術篇

1、手機 App 的技術棧手機 App 的技術棧可以分成三類原生 App 技術棧原生技術棧指的是&#xff0c;只能用于特定手機平臺的開發技術。比如&#xff0c;安卓平臺的 Java 技術棧&#xff0c;iOS 平臺的 Object-C 技術棧或 Swift 技術棧。混合 App 技術棧混合技術棧指的是開發混合…

《Java程序設計》學期總結

《Java程序設計》 學期總結 課程設計小組 -迦瓦棧隊 團隊博客 讀書筆記匯總第一周第二周第三周第四周第五周第六周第七周第八周第九周第十周 實驗報告匯總實驗一實驗二實驗三實驗四實驗五 代碼托管鏈接GitOSC 課程收獲與不足 上了一學期的課&#xff0c;收獲當然后很多&#xf…

012-- mysql的分區和分表

分區 分區就是把一個數據表的文件和索引分散存儲在不同的物理文件中。 mysql支持的分區類型包括Range、List、Hash、Key&#xff0c;其中Range比較常用&#xff1a; RANGE分區&#xff1a;基于屬于一個給定連續區間的列值&#xff0c;把多行分配給分區。 LIST分區&#xff1a;類…