I'm trying to call setState on the parent component in the beforeChange callback. This seems to disable the slider. However, calling setState in the afterChange callback works fine. Any ideas? Also, is there a jsfiddle that has a barebones setup of react-slick in it? I couldn't quite get one working.
I can corroborate this. Any setState call from within the beforeChange will cause the slider to update exactly once without animating. No further clicks to the next or previous buttons will change the current slide. This occurs even if the changed state property is not related to the slider.
here the same bug.
Did anyone solve this? I have the same problem, but this also happens sometimes when setting the state on the parent component on a button click.
Having the same issue, and have noticed it also occurs if you re-render the slider on prop change (e.g. when using redux's mapStateToProps after a new store is returned following a dispatched action)
+1
I found this problem about 6 month ago. I think the project is dead. It
need a fork or something :-/
On 21 Apr 2016 9:38 a.m., "Ivan Lyagushkin" [email protected]
wrote:
+1
—
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/akiran/react-slick/issues/136#issuecomment-212810395
+1
is smbody solved it ?
I guess this project is dead? Im sending this from my mailbox but anyway...
is long time since that and I didnt see an answer here.
On 30 September 2016 at 15:56, Alex [email protected] wrote:
is smbody solved it ?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/akiran/react-slick/issues/136#issuecomment-250766271,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAXxWwrQAzvZvV6Ox352Xchdcaw_EUsGks5qvSMngaJpZM4GIeKZ
.
Setting state of parent component in beforeChange is not a good idea, because it cause slider to re-render and effects animation
Can you replicate you usecase with this. I will try a work around
https://jsfiddle.net/kirana/20bumb4g/
I welcome PR's.
Has anyone found any solution?
The workaround I found for this is to avoid triggering a re-render by having whatever element you want to access the beforeChange parameter as a separate component.
For example I needed to have access to the active slide from a <SliderTabs> component. I attached a ref to it from my parent component this.sliderTabs and I did:
beforeChangeHandler(_, nextIndex) {
this.sliderTabs.setState({ activeTab: nextIndex });
}
Any news on this?
Even with afterChange and setState() is buggy. When it's rerendered my slider just scroll to the right automatically. Have to use @Grsmto's workaround.
Another workaround is to wrap the slider into a separate component and add
shouldComponentUpdate() {
return false;
}
to it.
I had the same problem with refreshing the page, what i did was sending the event.preventDefault(); then calling the next.slickNext();
It works!
It seems like setState from parent components causes problems from either beforeChange or afterChange.
Just want to +1 to @yantakus 's solution - I'm now using the main component to control rendering of slides and exciting other stuff and then having a simple slider container component.
@yantakus's solution seems to handle the use case.
Most people, on related issues, are claiming that setting state in any of beforeChange or afterChange hooks is causing the trouble. Please take a look at SlickGoTo example, this is somehow related to this. And I suppose that works just fine.
@laveesingh I think calling setState from those hooks is a valid use case.
I found that anything which trigger the component to re-render (for example forceUpdate), as well as changing the state or props, also breaks the carousel.
You shouldn't have to wrap the slider in a special component that ignores all updates anyway. What if you need to change the contents of the slider, or any of the settings?
I think this is something that needs to be fixed, or the library will seem broken to people who try it. It's a great slider; it should support being re-rendered. Earlier versions of this library didn't have that problem.
Can you reopen the issue?
@ClintonMorrison did you check this SlickGoTo example. I am setting state in afterChange hook, and that works just fine.
@laveesingh afterChange doesn't fit in most cases, when action is required immediately when a slide changes.
I completely agree with @ClintonMorrison and @yantakus - having setState inside beforeChange is an extremely valid case: be it analytics or changes/updates you want to trigger simultaneously.
@laveesingh - great example!
Essentially, I reckon you can toggle your shouldComponentRender prop (updateCount) between true and false, to get the same effect.
However it does forces your components to share and be aware of the short circuiting state.
The more complex state you have, the more props you'll need to pass into your SliderWrapper.
On the other hand, you'll need to update a single prop that will decide on whether it should be updated or not - rather than having react do it for you.
From your knowledge of the code, how hard it would be to prevent the slider from breaking from within the library itself?
@silicakes as long as my knowledge is concerned, here are the points that I'd like to state...
First of all the slider was not breaking, by the setState statement, it's just that the animation was gone during the slide change.
Secondly, if the Slider re-renders, the animation is supposed to go away. So I can't think of something (except for an additional prop, which is an overkill and is not acceptable) that can be done inside the library that would fix this.
Please correct me, if I'm wrong or you have something to suggest.
@laveesingh You're right with the fact that only the animation is affected, however it is never restored (after the update is finished).
That's why I'd go with looking weather the slider is being animated at the moment, if so, I'll push the update to a queue and will invoke it on transitionEnd.
For that, You'll still need to create another wrapping component - however this will be done internally:
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
sliderProps: props
}
this.transitioning = false;
}
componentWillReceiveProps(nextProps) {
if(this.transitioning) {
// store the update in a queue during the animation
updateQueue.push({sliderProps: nextProps});
} else {
// dispatch the update immediatly
this.setState({sliderProps: nextProps});
}
}
// short circuit the entire update cycle just in case the react team will decide to change its behavior (again)
shouldComponentUpdate() {
return !this.transitioning;
}
// releasing all the accumulated states
onTransitionEnd = () => {
while(this.updateQueue.length) {
let {sliderProps} = updateQueue.shift();
this.setState({sliderProps});
}
}
// child component will receive this function and will invoke it on every start/end of transition
onTransition = (isTransitioning) => {
if(isTransitioning !== this.transitioning) {
if(isTransitioning === false) {
onTransitionEnd();
} else {
//...you can do onTransitionStart here
}
}
this.transitioning = isTransitioning;
}
render() {
let {sliderProps} = this.state;
return <Slider {...sliderProps} onTransition={this.onTransition}>
}
}
What do you think?
This was fixed for me in the recent V0.21.0 release
No it wasn't. Still having the issue on V.0.23.1 @jmschlmrs
There is another workaround, not sure why this works or if this will work for everyone. Call setState inside a setTimeout:
beforeChange: (oldIndex, newIndex) => {
setTimeout( () => { this.setState({ var: value }); }, 10 );
}
The above fix with the setTimeout worked for me. Thanks @dixoncheng
Thanks, @dixoncheng your workaround worked for me as well
Most helpful comment
There is another workaround, not sure why this works or if this will work for everyone. Call
setStateinside asetTimeout: