I'm facing problem with my onClick function which is on a element. Without React-spring animations it works perfectly. But since I've added animations to it, function is not working. No errors in console, and I really can't find any problems like this on google. Have you encountered this type of problem?
Declaring an animation
import {useTransition, animated} from 'react-spring';
const gameOptionsTransitions = useTransition(showGameOptions, null, {
from: { opacity: 0, transform:'translateY(200px)' },
enter: { opacity: 1, transform:'translateY(0)' },
leave: { opacity: 0, transform:'translateY(200px)'}
});
In return
{gameOptionsTransitions.map(({ item, key, props }) =>
item &&
<animated.div key={key} style={props}>
<Link to="/play">
<a className="playerVsComputer-btn" onClick={props.playPlayerVsComputer}>Player vs. Computer</a>
</Link>
<Link to="/play">
<a className="playerVsComputer-btn" onClick={props.playPlayerVsPlayer}>Player vs. Player</a>
</Link>
<form onSubmit={handleSubmit}>
<input type="text" ref={sizeOfBoard} onChange={removeHighlightInput} autoFocus />
</form>
</animated.div>
)};
As you can see, both of a elements are wrapped in Link element. So after click, you will be redirected to that path but also function should be fired. This function is sent to this component from App.js as a prop. I've tried to move whole onClick={props.playPlayerVsComputer} from a element to Link but nothing changes.
Sent function
function playPlayerVsPlayer(){
setPlayerVsPlayer({
AI:false,
AImove:false
});
setDimensions({
rows:"3",
columns:"3"
})
generateMatrix(3,3);
}
This function sets dimensions state and then create matrix according to these dimensions. Then generateMatrix function fires another function, which renders rows x columns table to App. But it's not that important because there will be problem with that animated div, not with these functions.
I've changed animated div like this, so Link element don't have any other elements inside, also classNames moved to Link element.
{gameOptionsTransitions.map(({ item, key, props }) =>
item &&
<animated.div key={key} style={props}>
<Link to="/play" className="setGameMode-btn" onClick={playPlayerVsComputer}>
Player vs. Computer
</Link>
<Link to="/play" className="setGameMode-btn" onClick={playPlayerVsPlayer}>
Player vs. Player
</Link>
<form onSubmit={handleSubmit}>
<input type="text" ref={sizeOfBoard} onChange={removeHighlightInput} autoFocus />
</form>
</animated.div>
)};
For onClick events I have created two new functions which are calling these functions from App.js as a props.
//Fire animations sent as a props
function playPlayerVsComputer(){
props.playPlayerVsComputer();
}
function playPlayerVsPlayer(){
props.playPlayerVsPlayer();
}
You are adding a react spring transition which have its own props ,
All you have to do just rename the props => to other name (annimationProps by example ) in order to not confuse the props passed to your component by the App file
as below :
{gameOptionsTransitions.map(({ item, key, annimationProps }) =>
item &&
<animated.div key={key} style={annimationProps}>
<Link to="/play">
<a className="playerVsComputer-btn" onClick={props.playPlayerVsComputer}>Player vs. Computer</a>
</Link>
<Link to="/play">
<a className="playerVsComputer-btn" onClick={props.playPlayerVsPlayer}>Player vs. Player</a>
</Link>
<form onSubmit={handleSubmit}>
<input type="text" ref={sizeOfBoard} onChange={removeHighlightInput} autoFocus />
</form>
</animated.div>
)};
Related
I'm building a multi tab chat like UI using react and antd, it looks like image below.
On the left side you can see multiple tabs showing last names using antd Tabs, on the right side I'm using antd comments to display each comment on the conversation thread
Now, the issue is that I'm trying to use useRef so it scrolls automatically to bottom when a new message is sent, and my code works, but only if I'm on the first tab or on the last one but no with the one on the middle and I'm stuck on finding out why
This is my code:
//reference and scroll function
const myRef = useRef(null);
const executeScroll = () => {myRef.current.scrollIntoView({ behavior: "smooth" })};
//useEffect associated to the source of the chat messages array
useEffect(executeScroll, [BuzonDataAgrupado]);
//And the Tab component
<Tabs tabPosition='left' onChange={handleTabChange}>
{
Object.entries(BuzonDataAgrupado).map(([tabName, mensajes]) => {
return(
<TabPane tab={tabName} key={tabName}>
<Card className='buzon-container'>
<div style={divStyle}>
{mensajes.map((mensaje) => {
return(
<Comment className='buzon-message-sent'
key={mensaje._id}
author={<a>{mensaje.nombreFamilia}</a>}
content={<p>{mensaje.Texto}</p>}
datetime={
<Tooltip title
{moment(mensaje.Fecha).format('YYYY-MM-DD HH:mm:ss')}>
<span>{moment(mensaje.Fecha).fromNow()}</span>
</Tooltip>}/>
)//return
})} //map
//This is the reference where is scrolls to at the end of message list
<div ref={myRef}></div>
</div>
<Divider />
<div className='buzon-message-editor'>
<Form.Item>
<TextArea rows={2} onChange={handleMensajeChange} value={NuevoMensaje} />
</Form.Item>
<Form.Item>
<Button htmlType="submit" loading={SendingMessage} onClick={sendMessage} type="primary">Enviar mensaje</Button>
</Form.Item>
</div>
</Card>
</TabPane>
)})
}
</Tabs>
Thoughts?
Have you debugged the myRef? Does it get always reassigned to the proper div when you change tab?
I cannot see why your code wouldn't work, but I have an idea for a workaround:
give the div an id
find the element by the id and use that to scroll
document.getElementById('your-div-id').scrollIntoView({ behavior: 'smooth' })
You could improve this if you put ref on the <Tabs> component (or its parent if it's not possible) and then you could use
tabsRef.current.getElementById('your-div-id').scrollIntoView({ behavior: 'smooth' })
Note that in javascript it might be a good idea to first test if the result of getElementById('your-div-id') is not null or undefined.
I'm trying to create a simple app where if you click on a button, a modal overlay appears, and if you click on the 'x' in the modal it disappears.
I made a component for my button, called ShowOffer, and I have an onclick on it which toggles the boolean value of modalVisible, which is a piece of state.
However, nothing happens when I click on it.
I made another button element with the same onclick, and it seems to work fine.
Here is a code sandbox
You are adding onClick on the ShowOffer component, but here you are just passing it as a prop in it.
<ShowOffer display={"block"} onClick={toggleVisibility} />
is same as
React.createElement(ShowOffer, {
display: "block",
onClick: toggleVisibility
});
Under the hook, you are just passing an argument to a function
You have to add onClick event on the button in ShowOffer component as:
Live Demo
<button
style={{ display: `${display}` }}
onClick={toggleVisibility}
className="show-offer"
>
Show Offer
</button>
and you have to pass the toggleVisibility callback to ShowOffer as:
<ShowOffer display={"block"} toggleVisibility={toggleVisibility} />
This is the simple logic. Your ShowOffer component is not identify the onclick event and this component's button is not have any event handlers. So you just pass the event or directly pass the function name for access the event. Passing props name is the important one.
<ShowOffer display={"block"} onClick = {toggleBox}/>
export default function ShowOffer({ display, onClick}) {
return (
<button style={{ display: `${display}` }} className="show-offer" onClick={onClick}>
Show Offer
</button>
);
}
or
<ShowOffer display={"block"} toggleBoxFunct = {toggleBox}/>
export default function ShowOffer({ display, toggleBoxFunct }) {
return (
<button style={{ display: `${display}` }} className="show-offer" onClick={toggleBoxFunct}>
Show Offer
</button>
);
}
You can use concept of Callbacks,
App.js, make following changes,
pass toggleVisibility={toggleVisibility} as props, no need to mention onClick at component but at button
return (
<div className="App">
<Modal display={modalVisible ? "flex" : "none"} />
<ShowOffer display={"block"} onClick={toggleVisibility} toggleVisibility={toggleVisibility}/>
<button onClick={toggleVisibility}>Button</button>
</div>
);
ShowOffer.js, props passed function, call that function here with onclick,
import React from "react";
import "./ShowOffer.css";
export default function ShowOffer({ display, toggleVisibility }) {
return (
<button style={{ display: `${display}` }} onClick={toggleVisibility} className="show-offer">
Show Offer
</button>
);
}
working solution is here, https://codesandbox.io/embed/modal-overlay-tnis9?fontsize=14&hidenavigation=1&theme=dark
So I have two .js files (are they also called modules?). The first .js file is a class-based component. It has handleClick() as well as render(). It looks like this (I've actually removed a lot of the code to make it appear shorter here):
handleClick(event) {
event.preventDefault()
console.log('handleclick')
this.initializeFetchApiAndSetState()
}
//Helper Function
checkGuessForCorrectAnswer() {
console.log('correct answer!')
}
render() {
return (
<div className="container-main">
<MultipleChoices
onClick={this.handleClick}
data={this.state.guess1}
/>
<button
className='Submit'
onClick={this.handleClick}
>
Submit
</button>
</div>
)
}
The button above works fine in that I can click on it and it'll console log the word 'correct answer!'. But for some reason, when I try to pass onClick to the "MultipleChoices" file/module it doesn't console log 'correct answer!'. The MultipleChoices.js file looks like this:
import React from "react"
function MultipleChoices(props) {
return(
<div>
<div className="button-grid">
<button
className="btn"
value={props.data}
onClick={props.handleClick}
>
{props.data}
</button>
</div>
</div>
)
}
export default MultipleChoices
Why can the button activate onClick in the first file, but not when I try to pass onClick to the MultipleChoice.js (which also has a button)?
In your upper component, you need to replace the onClick property with a handleClick property.
<MultipleChoices
handleClick={this.handleClick}
data={this.state.guess1}
/>
Because inside the Multiple Choices component you are calling the handleClick method from the properties (which is not set)
In your parent component you have given name to your property as onClick, while you are trying to acces it in children component as prop.handleClick.
This my code sandbox example:
https://codesandbox.io/s/react-hooks-counter-demo-kevxp?file=/src/index.js
My problem is:
The list will always rerendering on every state change inside the page so the scroll will always back to the top. I want to know why this happen, and how to prevent this behaviour even the state of the list have changes then keep the last scroll position of the list
Every time App renders, you are creating a brand new definition for the Example component. It may do the same thing as the old one, but it's a new component. So react compares the element from one render with the element of the next render and sees that they have different component types. Thus, thus it is forced to unmount the old one and mount the new one, just as it would if you changed something from a <div> to a <span>. The new one begins scrolled to 0.
The solution to this is to create Example only once, outside of App.
const Example = props => (
<List
className="List"
height={80}
itemCount={props.propsAbc.length}
itemSize={20}
width={300}
itemData={{
dataAbc: props.propsAbc
}}
>
{({ index, style, data }) => (
<div className={index % 2 ? "ListItemOdd" : "ListItemEven"} style={style}>
{data.dataAbc[index]}
</div>
)}
</List>
);
function App() {
const [count, setCount] = useState(0);
let [dataArray, setDataArray] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
return (
<div className="App">
<h1>Scroll down the blue box, then click the button</h1>
<h2>You clicked {count} times!</h2>
<button onClick={() => setCount(count - 1)}>Decrement</button>
<button onClick={() => setCount(count + 1)}>Increment</button>
<div
style={{ maxHeight: "80px", overflow: "äuto", background: "lightblue" }}
>
<Example propsAbc={dataArray} />
</div>
</div>
);
}
https://codesandbox.io/s/react-hooks-counter-demo-qcjgj
I don't think it's a react window problem.
A react component re-renders because there's a state change. In this case, the state change is caused by setCount (when you click the increment button), which re-renders the entire component including Example.
If Example is its own component, the scroll position won't get refreshed, because it no longer depends on the count state.
A working sample here:
https://codesandbox.io/s/react-hooks-counter-demo-hbek7?file=/src/index.js
Hey is there a smarter way to redirect a click from a button to file input element ?
Currently I'm using:
function clickRedirect() {
document.getElementById("uploadFileButton").click();
}
Works. However I've been clearing any DOM manipulation (outside of appState) in my react project and this is the last bit remaining. I'd like to get rid of it.
You can use ref with hidden button
<input id="myInput" type="file" ref={(ref) => this.myInput = ref} style={{ display: 'none' }} />
<FloatingActionButton
className="floatingButton"
backgroundColor='#293C8E'
onClick={(e) => this.myInput.click() }
>
</FloatingActionButton>
attached demo here:
https://jsfiddle.net/432yz8qg/58/