React-leaflet: How to pass dynamic HTML/jsx/react component inside bindPopup? - reactjs

I want to pass a react component or jsx code to the bindPopup function but it accepts string as input. I tried using ReactDOMServer.renderToString as shown below but the popup is not dynamic. I want an onClick event to be registered inside the PopupTemplate component. Is there any better alternative:
Code:
layer.bindPopup(
ReactDOMServer.renderToString(
<PopupTemplate
layerId={layerId}
/>
)
);
Behaviour:
I can't use the Popup component here as the layer is a drawn polygon using react leaflet draw.

Related

#testing-library/React : Clicking outside of component not working

I'm using react testing library to test my component built with FluentUI.
Here is link:
https://codesandbox.io/s/keen-borg-2tqmj?file=/src/App.spec.js
The code is basically a pasted snippet of the example code of Dialog component from FluentUI docs site. The behavior that I'm testing is:
User opens the dialog
User clicks outside of the dialog
onDimiss prop of the component should be fired.
It works when I'm playing with it manually however it seems that I failed to simulate a click outside of the component with testing library.
I tried using userEvent.click(document.body) as mentioned in this post but got no luck
Does anyone has any idea how to make test work?
It is not working because the Dialog component is not listening for the onClick event on the body, so what you need to do in this case is to find the actual element that is being clicked, observing the dom you'll find that the overlay is a div with some overlay classes on it.
<div
class="ms-Modal is-open ms-Dialog root-94"
role="document"
>
<div
aria-hidden="true"
class="ms-Overlay ms-Overlay--dark root-99"
/>
The problem now is to find a way to select it. Unfortunately, you cannot select elements in RTL by their className, so you need to use another selector; in this case, we can get the parent element by the role and then access the first child.
const onDismiss = jest.fn();
const { getByRole } = render(<App onDismiss={onDismiss} />);
UserEvent.click(screen.getByText("Open Dialog"));
const document = getByRole("document");
UserEvent.click(document.firstChild);
expect(onDismiss).toHaveBeenCalled();
https://codesandbox.io/s/hungry-joliot-tjcph?file=/src/App.spec.js

React change class of component without using state

How can I change the className or style of a div without using state or any third party libraries? Lets say I click on a button, and I need to change the background color of a div how can I do that?
<Affix onChange={() => change css or class} offsetTop={60}>
<div>...</div> // Change css of this div
</Affix>
You can change any attribute or property of a Component (Element) in React by using basic javascript functions.
onClick={(e) => {
e.currentTarget.setAttribute("src", newUrl);
}
Will change an image the moment you click on it, without using Ref or State.
event.currentTarget will give you the reference to the component that fired that particular React.MouseEventHandler event, and with the Element's reference, you can manipulate it at will.
This is particularly useful when you need to change an attribute in a component in a map loop without needing to keep track of it.
Edit:
A friend of mine just gave me a better one for classes in specific:
e.currentTarget.classList.add('my_custom_klass')
You can either do it manually using state:
const [myClass, setMyClass] = useState('bgColor-white');
return (
<Affix onChange={() => setMyClass('bgColor-black')} offsetTop={60}>
<div className={myClass}>...</div> // Change css of this div
</Affix>
)
Or you can use a library that handles dynamic styling. I use and recommend styled-components

React Context always returns EMPTY

I have a Search parent component and a SideBar child component, I am trying to get context in SideBar, but everytime it returns empty.
I followed the tutorial exactly like: https://itnext.io/manage-react-state-without-redux-a1d03403d360
but it never worked, anyone know what I did wrong?
Here is the codesandbox link to the project: https://codesandbox.io/s/vigilant-elion-3li7v
I wrote that article.
To solve your specific problem:
When using the HOC withStore you're injecting the prop store into the wrapped component: <WrappedComponent store={context}.
The value of the prop store is an object that contains 3 functions: get, set, and remove.
So, instead of printing it, you should use it. For example this.props.store.get("currentAlbums") or this.props.store.set("currentAlbums", [album1, album2]).
This example is forked by your code: https://codesandbox.io/s/nameless-wood-ycps6
However
Don't rewrite the article code, but use the library: https://www.npmjs.com/package/#spyna/react-store which is already packed, tested, and has more features.
An event better solution is to use this library: https://www.npmjs.com/package/react-context-hook. That is the new version of the one in that article.
This is an example of a sidebar that updates another component content: https://codesandbox.io/s/react-context-hook-sidebar-xxwkm
Be careful when using react context API
Using the React Context API to manage the global state of an application has some performance issues, because each time the context changes, every child component is updated.
So, I don't recommend using it for large projects.
The library https://www.npmjs.com/package/#spyna/react-store has this issue.
The library https://www.npmjs.com/package/react-context-hook does not.
You pass the store as a prop, so to access it, you need this.props.store in your SideBar.
Not this.state.store
Create a wrapping App component around Search and Sidebar:
const App = props => (
<div>
<Search />
<SideBar />
</div>
);
export default createStore(App);
Now you can manipulate state with set and get that you have available in child components Search and Sidebar.
In Search component you can have something like:
componentDidMount() {
this.props.store.set("showModal", this.state.showModal);
}
also wrapped with withStore(Search) ofc.
and in SideBar you can now call:
render() {
return (
<div>
{"Sidebar: this.state.store: ---> " +
JSON.stringify(this.props.store.get("showModal"))}
}
</div>
);
}
and you will get the output.

React decorator with dynamic param

I have a simple decorator and a react native component that is decorated like this:
#withData('apple')
class Screen extends Component {
}
I need to pass the parameter to #widhData dynamically. Based on the screen user has selected. But outside class I don't have access to props and so on.
How can pass dynamic parameters to the decorator based on the param passed on navigation ?
Thanks.

catch keydown events in inner components using react-keydown

I'm using react-keydown library for adding keyboard shortcuts to my application, but can't make it work in inner dialogs components. The dialogs are not always visible, but I expect the keys to work when they are visible.
I'm getting to event_handlers.js._onKeyDown(event) method, but with missing value: fn = undefined, whereas fn should contain the decorated function.
My components looks like:
<Container>
<MyDialog>
<material-ui-dialog/>
</MyDialog>
</Container>
Container.js:
import keydown from 'react-keydown'
class Container extends Component {
#keydown('enter')
someMethod1(){
// working
}
render() {
return (
<div>
<MyDialog/>
</div>
)
}
}
MyDialog.js:
import keydown, {keydownScoped} from 'react-keydown'
#keydown('enter')
class MyDialog extends Component {
#keydownScoped('enter')
someMethod3(){
// not working
}
}
Based on your description in the comments, the issue appears to be that your Dialog components mount and then lose focus so any keybindings inside them will not receive the keystrokes. You have a couple of options:
1) Expand the scope of the keybinding by decorating a component that is an ancestor of your Dialog components and won't lose focus. In an extreme case this could be the root component of your app. Then decorate the desired Dialog component method with keydownScoped. Inside that method examine the props to make sure the current dialog is the active one.
2) Programmatically activate your Dialog keybindings along the lines of this https://github.com/glortho/react-keydown/issues/28.
Hope that helps!

Resources