[英]I am trying to animate an array of letters in my React Hangman App
I am trying to use react-spring to have letters from an array animate in and out for my Hangman App.我正在尝试使用 react-spring 让来自数组的字母为我的 Hangman 应用程序进出动画。 I want them to fade in on load, and fade out when removed from the array.
我希望它们在加载时淡入,并在从阵列中移除时淡出。 They are removed from the array on click.
单击时它们会从阵列中删除。 For now I just want them to fade in and out.
现在我只想让它们淡入淡出。 The closest I got was the same buttons as before, but it was laggy and didn't animate at all.
我得到的最接近的是和以前一样的按钮,但它很迟钝,根本没有动画。
I have tried using Spring components, Transition Components, and useTransition.我尝试过使用 Spring 组件、Transition 组件和 useTransition。
This is the most recent example I was trying to work off of.这是我试图解决的最新示例。 codesandbox
密码箱
const App = () => {
const [availableLetters, setAvailableLetters] = useState([
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z'
])
const location = useLocation()
const transitions = useTransition(location, location => location.pathname, {
from: { opacity: 0, transform: 'translate(100%,0)' },
enter: { opacity: 1, transform: 'translate(0,0)' },
leave: { opacity: 0, transform: 'translate(-50%,0)' }
})
return (
<Fragment>
<Header defaultGuesses={defaultGuesses} />
{msgAlerts.map((msgAlert, index) => (
<AutoDismissAlert
key={index}
heading={msgAlert.heading}
variant={msgAlert.variant}
message={msgAlert.message}
/>
))}
{/* routes */}
<main className="container">
{transitions.map(({ item, props, key }) => (
<animated.div native='true' key={key} style={props}>
<Switch location={item}>
{/* home */}
<Route
exact
path="/"
render={() => (
<Welcome
msgAlert={msgAlert}
resetAllButSecret={resetAllButSecret}
setSecret={setSecret}
/>
)}
/>
<Route
exact
path="/guesses"
render={() => (
<Guesses
msgAlert={msgAlert}
secret={secret}
setGuesses={setGuesses}
resetAllButSecretAndGuesses={resetAllButSecretAndGuesses}
setDefaultGuesses={setDefaultGuesses}
/>
)}
/>
<Route
exact
path="/play"
render={() => (
<Play
guesses={guesses}
availableLetters={availableLetters}
correctLetters={correctLetters}
incorrectLetters={incorrectLetters}
secret={secret}
setSecret={setSecret}
pushToCorrect={pushToCorrect}
pushToIncorrect={pushToIncorrect}
removeAvailable={removeAvailable}
msgAlert={msgAlert}
resetBoard={resetBoard}
gameOver={gameOver}
setGameOver={setGameOver}
setGuesses={setGuesses}
resetGame={resetGame}
/>
)}
/>
</Switch>
</animated.div>
))}
</main>
</Fragment>
)
}
export default App
import { Spring, animated, Transition } from 'react-spring/renderprops'
import ClickableLetter from './ClickableLetter'
const AnimatedLetter = animated(ClickableLetter)
const Play = ({'tons of props i'm not showing'}) => {
const availHTML = availableLetters.map((letter, index) => (
<Transition
from={{ opacity: 0 }}
to={{ opacity: 1 }}
leave={{ opacity: 0 }}
// config={config.slow}
key={`${letter}_${index}`}
>
{styles => (
<AnimatedLetter
style={styles}
pushToCorrect={pushToCorrect}
pushToIncorrect={pushToIncorrect}
secret={secret}
removeAvailable={removeAvailable}
letter={letter}
gameOver={gameOver}
msgAlert={msgAlert}
/>
)}
</Transition>
))
return (
<AbsoluteWrapper>
<Fragment>
{availHTML}
</Fragment>
</AbsoluteWrapper>
)
}
const availHtml = availableLetters.map(letter => (
<ClickableLetter
key={letter}
pushToCorrect={pushToCorrect}
pushToIncorrect={pushToIncorrect}
secret={secret}
removeAvailable={removeAvailable}
letter={letter}
gameOver={gameOver}
msgAlert={msgAlert}
/>
))
import React from 'react'
import { withRouter } from 'react-router-dom'
import { PrimaryButton } from '../Shared/Styled'
// these are the green letters used to let a user guess a letter
const ClickableLetter = ({
letter, secret, pushToCorrect, pushToIncorrect, removeAvailable, gameOver, msgAlert
}) => {
// this function is used to either push the value to a correct or incorrect array causing an app wide state change and re render
const pushValue = () => {
if (!gameOver) {
if (secret.toLowerCase().includes(letter)) {
pushToCorrect(letter)
} else {
pushToIncorrect(letter)
}
// take it from the availLetter arr to re-render this component with one less letter
removeAvailable(letter)
} else {
msgAlert({
heading: 'Oops!',
message: 'Game is over, please click reset to play again',
variant: 'danger'
})
}
}
return (
<PrimaryButton onClick={pushValue}>{letter}</PrimaryButton>
)
}
export default withRouter(ClickableLetter)
const transitions = useTransition(availableLetters, item => item, {
from: { opacity: 0},
enter: { opacity: 1},
leave: { opacity: 0}
})
const availHTML = transitions.map(({ item, props, key }) =>
<AnimatedLetter key={key} style={props}
pushToCorrect={pushToCorrect}
pushToIncorrect={pushToIncorrect}
secret={secret}
removeAvailable={removeAvailable}
letter={item}
gameOver={gameOver}
msgAlert={msgAlert}/>
)
My other attempt was using an animated.div instead of animated(ClickableLetter) with the ClickableLetter rendered inside of the div.我的另一个尝试是使用动画.div 而不是动画(ClickableLetter),ClickableLetter 呈现在 div 内。 Something like this.
像这样的东西。 (Don't have the code so this isn't exact)
(没有代码所以这不准确)
const availHTML = transitions.map(({ item, props, key }) =>
<animated.div key={key} style={props}><ClickableButton letter={item}/> </animated.div>
))
Okay I figured it out after a while.好吧,过了一会儿我想通了。 First I needed to make my custom component animation ready...
首先,我需要准备好我的自定义组件 animation...
const AnimatedClickableLetter = animated(ClickableLetter)
Then I used the Transition component, I still haven't figured out how to do this with useTransition.然后我使用了Transition组件,我仍然没有弄清楚如何使用useTransition来做到这一点。 I tried but it wasn't getting anywhere.
我试过了,但没有成功。
const availHTML = (
<Transition
items={availableLetters} // the array
keys={item => item} //unique keys, in this instance, the letter is fine
from={{ opacity: 1 }} // animation props
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}
>
{letter => props => //for each letter, make an AnimatedClickableLetter..
//props will be the animation style.
<AnimatedClickableLetter
style={props} //here's where we pass it in as props.
pushToCorrect={pushToCorrect}
pushToIncorrect={pushToIncorrect}
secret={secret}
removeAvailable={removeAvailable}
letter={letter}
gameOver={gameOver}
msgAlert={msgAlert}
/>
}
</Transition>
)
Finally, the step that took me forever to figure out... Add the style to the custom component itself.最后,让我永远弄清楚的步骤......将样式添加到自定义组件本身。
const ClickableLetter = ({
letter, secret, pushToCorrect, pushToIncorrect, removeAvailable, gameOver, msgAlert, style //accept the prop here...
}) => {
// this function is used to either push the value to a correct or incorrect array causing an app wide state change and re render
const pushValue = () => {
if (!gameOver) {
if (secret.toLowerCase().includes(letter)) {
pushToCorrect(letter)
} else {
pushToIncorrect(letter)
}
// take it from the availLetter arr to re-render this component with one less letter
removeAvailable(letter)
} else {
msgAlert({
heading: 'Oops!',
message: 'Game is over, please click reset to play again',
variant: 'danger'
})
}
}
return (
// add the style to the button, here.
<Fragment>
- <PrimaryButton onClick={pushValue}>{letter}</PrimaryButton>
+ <PrimaryButton style={style} onClick={pushValue}>{letter}</PrimaryButton>
</Fragment>
)
}
export default ClickableLetter
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.