I am using React-Slick (https://github.com/akiran/react-slick) for my project.
I want to be able to dynamically change the settings that I provide to my slider.
For slickjs (https://github.com/kenwheeler/slick) this can be done using slickSetOption.
I realized that this is not possible in React Slick after reading documentation.
The following was also posted by one of the contributors to the plugin:
slickSetOption will not be implemented, those effects be achieved by
passing props via state from the wrapper component
This made me think that it should be possible to in fact change the settings of the slider in a dynamic way.
My implementation looks like this
<Slider
dots={true}
infinite={true}
speed={500}
slidesToShow={1}
slidesToScroll={1}
autoplaySpeed={2000}
autoplay={props.autoplay} // even if the value is changed, autoplay stays to it's initial setting
>
{images}
</Slider>
Using React Slick's playground I've put together this to demonstrate the issue:
https://codesandbox.io/s/react-slick-playground-unyot
What am I missing here?
I think this is a bug in the component, probably some internal state is not changed. As a workaround, you can change the key prop when the autoplay prop change, this will force the Slider component to be recreated :
state = {
dots: true,
autoplay: false,
sliderKey: Date.now()
};
useAutoplay() {
this.setState({
autoplay: true,
sliderKey: Date.now()
});
}
<Slider key={this.state.sliderKey} {...this.state}>
</Slider>
Complete code : https://codesandbox.io/s/react-slick-playground-dx957
Related
Darkmode works everywhere in my react app, except on a headless ui combobox. I put a styled h1 in the same component and applied dark:bg-red-200(and any other style) no problem. The combobox accept all other tailwind utilities including attibutes like hover: but not the dark: property.
For others (such as me) stumbling upon this:
E.g. the Dialog-component (and I assume others too) render right in the body tag (source)
If you are using "the class strategy" to handle dark mode (i.e. adding a "dark" class to the wrapper) this will be a problem, because the class is not anymore parent to the Dialog
Solution I ended up using:
I ended up using useEffect to add the dark class to the body:
useEffect(() => {
if(darkMode){
document.body.classList.add('dark')
}else{
document.body.classList.remove('dark')
}
}, [darkMode])
I use Webpack 4, Babel 7, React 16.8. My app loads google web fonts, external images required by many components taking part in the initial rendering when users load my pages.
I load fonts with a sass file like this:
#import url('https://fonts.googleapis.com/css?family=Roboto:300,400,700');
I use images within all components like this:
import SearchSvg from '../../images/search_icon.svg';
and use them like this:
<img src={ SearchSvg } />
Now I know about <img onLoad=.....> and I know there are packages out there to test whether web fonts are already loaded. My question is: Is there any SYSTEMIC way/pattern to get the initial rendering of the React components wait until all those external resources are loaded?
Right now I use setTimeout with 500 ms to delay the root rendering in my index.js.
setTimeout(function() {
render(
...
);
}, 500);
I would LOVE to replace this hard-coded value with something that actually knows when everything's loaded -- Ideally without having to Add code in every single Component I use.
The motivation is of course to avoid Font/Image flickering when I initially render my app -- due to the rendering while images/fonts aren't fully loaded yet.
You may render your root component after onload event is fired.
The load event is fired when the whole page has loaded, including all dependent resources such as stylesheets images.
https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
window.onload = function() {
ReactDOM.render(<App/>, document.getElementById('root'));
};
If your purpose is to increase performance then I would highly recommend to consider Server Side Rendering.
In your case, you could use document.fonts.ready to check if the font is ready, and then conditionally render the parts you want once this is true
An example of this is found here:
https://developer.mozilla.org/en-US/docs/Web/API/Document/fonts
For your use case, you could use a similar function found at the above link, then set a state value to true if its ready. Then you could conditionally render what you want once this is true
For example:
Call the function in componentDidMount:
componentDidMount() {
this.isFontLoaded()
}
The function uses document.fonts.ready, which returns a promise. We then set the state value fontReady to true once the promise returns:
isFontLoaded = () => {
document.fonts.ready.then(this.setState({ fontReady: true }))
}
Only render the the things you want if fontReady is true:
{fontReady && <img src={ SearchSvg } />}
You can use a wrapper component to do all the checks and show a loading or nothing when that's happening and when everything is done, render the application. Something like:
class LoadApplication {
state = { loaded: false }
timer = null
componentDidMount() {
this.timer = setInterval(this.checkStuff, 50)
}
componentWillUnmount() {
clearInterval(this.timer)
}
checkStuff() {
if (stuffIsLoaded) {
this.setState({ loaded: true })
}
}
render() {
return this.state.loaded ? this.props.children : null;
}
}
...
ReactDOM.render(<LoadApplication><App /></LoadApplication>, document.querySelector('#root'))
This is kinda the same way CRA handles errors. The same way is recommended to catch errors in components in React's documentation so I think it might be what you're looking for. I hope it helps.
I have a react component which has props coming from the redux store. I need to do animation for icon from this component each time when I got new props. I change state when my component gets props on componentWillUpdate(). In this way I can get animation but just the first time, then I already have this class in DOM element and new update doesn't call animation. How I see I have to delete class which provides animation from DOM, but I am not sure when to do it. I don't buttons, I have just props comes and each time when it happens I need the animation. I read that there is a way with refs, but I don't know how to use refs in such situation
Let us assume that the animation which is triggered on receipt of new props is a bounce animation, which is triggered once a bounce-class class is appended to the desired HTML element.
Instead of componentWillUpdate, I utilise the componentDidUpdate life cycle method, since I wish to call a setState when the required prop is updated. It takes the previous props and the previous state. Let us assume, that the prop which we are watching for changes is bounceProp.
componentDidUpdate(prevProps, prevState) {
if (prevProps.bounceProp !== this.props.bounceProp) {
this.setState({ shouldBounce: true });
}
}
React relies on Synthetic Events, which also includes animation-events. We use the onAnimationEnd event on the desired element, to make shouldBounce: false.
<div
className={
this.state.shouldBounce ? "bounce-class other-class" : "other-class"
}
onAnimationEnd={() => this.setState({ shouldBounce: false })}
/>;
Here the bounce-class class which is responsible for the animation, automatically removes and applies itself based on the shouldBounce variable.
I am using React dropzone for file upload
<DropZone
accept='.pdf,.pptx,.ppt,.docx,.doc,.xls,.xlsx,.xslx,.png,.xsl,.jpg,.jpeg,.gif,.zip'
onDrop={ files => {
this.handleFileDrop(files);
this.dragLeaveHandler();
} }
onDragEnter={ this.dragOverHandler }
onDragLeave={ this.dragLeaveHandler }
multiple={ false }
style={ { height: '100%' } }
>
dragOverHandler = () => {
console.log('enter');
this.setState({
isDragOver: true,
});
};
dragLeaveHandler = () => {
console.log('exit');
this.setState({
isDragOver: false,
});
};
When a file is moving above the drop zone onDragLeave event fires simultaneously.
Should I use some other events?
How can I fix this issue?
You could use pointer-events: none; on the element(s) that are firing the drag leave. That should still allow the dropped event and getting the accepted file though would stop overriding the dropzone events.
The problem you're facing is most likely caused by the DOM events dragEnter and dragLeave getting messed up instead of any flaw in the react-dropzone package. Some elements may cause hovering over them in certain positions not to register as hovering over their parent element. For example, there is a thin sliver at the top edge of any plain string rendered inside a block displayed element. Most commonly this happens inside a <p> tag.
Without seeing the children rendered inside your dropzone, it is impossible to give a specific fix. Generally, you will have to mess with the styling of the children, though. <p> tags for example will not be a problem if their size is set to 0 pixels or if they're replaced with <span> tags. Both options will disrupt the displaying of the children, which is unfortunatley unavoidable.
As for using other events, you're out of luck. The DropZone component relies on the onDragEnter and onDragLeave HTML DOM events. Therefore any fix you might come up with won't fix the component itself.
All in all, it's an unfortunate issue that just has to be dealt with. The simplest way to deal with it is to just have at most one piece of text inside the dropzone and to set its size to 0 pixels with css: height: 0px;. Regular <div> elements won't cause issues, so you can craft an intricate dropzone using them.
I have a large React app and I have a few components that I would like to completely disable from a config or global level. Is there any kind of global hook that I can use that is called before any component is rendered? If so, I imagine I can check the name of the component and return null if the name is on the disabled list. How would you do this?
There are a lot of ways to do this:
React's Context API allows you pass props through every level of the component tree so you can use them as flags to enable/disable components. Should be used sparingly however.
Higher Order Components are basically just functions that return a component. You could wrap your components in logic to render them as needed.
Or of course you could use a global state manager like redux to set global states.
There are many ways to do this, so, I'll just describe one simple way: using references and updating the states accordingly.
Full working feature hide/showing sandbox online: codesandbox.io ReactJS Feature Hide/Show Demo
Defined are two classes, class Feature extends React.Component and class App extends React.Component. The render() for <Feature/> is...
render() {
if (!this.state.enabled) {
return <div />;
}
return (
<div className="Feature">
<h1>My Feature!</h1>
</div>
);
}
And the option for enabling/disabling a feature in <App /> would handle display/hiding like so...
handleOnClick(e) {
if (e.target.checked) {
this.feature.setState({ enabled: true });
} else {
this.feature.setState({ enabled: false });
}
}
Of course, you need to make sure that <Feature /> has the reference set...
<Feature
ref={instance => {
this.feature = instance;
}}
/>
If you need simplest solution just use browser global vars and check it in render.
render() {
if( window.globalFlag ) return null
return (
<div> feature content...
Drawbacks:
modifying component,
using global scope,
some unnecessary code can be run earlier (f.e. constructor) and later (f.e. componentDidMount).
Use HOCs - wrap your component - connecting with global store using redux or context API.
<FlagsProvider store={flagStore}>
<SomeComponent_1>
<SomeComponent_2>
<FlagsConsumer flag="someFeatureFlag">
<SomeFeatureComponent />
<FlagsConsumer/> connects to store (redux connect would be an inner wrapper - composing HOCs) and conditionally renders <SomeFeatureComponent /> (or null).
Of course HOC can pass received props to wrapped component - it can be functionally transparent.
Don't reinvent the wheel - use some ready module, read tutorials, google for sth suitable.
HOC can also play a role of A/B testing.