In my React app using Hooks, I am using a AgGrid and want to invoke some function within cellRenderer.
{
headerName: 'Link Text',
field: 'someId',
width: 160,
cellRenderer: renderLinkRenderer
}
Below is my renderLinkRenderer;
import React from 'react';
export default (props) => {
const goToDetails = (params) => {
//How do I invoke this function ?
}
return {props.value}
};
Using onClick as above does not invoke the function. What can I try next?
You are calling the function instead, however onClick takes a function as argument, not its return value, so you just have to remove the parenthesis:
return {props.value}
Related
rowTooltip: (createElement, cell, property, context) => {
return withDirectives(createElement("div", "any value"), ["tooltip", "is this the tooltip value?", "is this the value actually?", "no this is the value argument"]);
},
how do I render this tooltip directive : https://www.primefaces.org/primevue/tooltip
inside a render function loop inside a functional component with vue3.
I've been trying for hours
added a fork with my problem
vue3 has function h
using with setup function:
setup() {
const tooltip = resolveDirective('tooltip');
return () => {
const vnode = withDirectives(
h(Button, { label: "I'am dynamic button, hover me too" }),
[[tooltip, 'tooltip directive with render function']]
);
return vnode;
};
}
example: https://stackblitz.com/edit/vue-gg76si?file=src/main.js
Back in vue 2 i used to call render() like that:
export default {
mounted(){
...
},
render(){
...
},
methods(){
...
}
}
I'm now trying to do the same with Vue 3 and the composition api. Here is what i tried:
export default {
...
setup(props, context){
...
const create_canvas = (h, id, props) => {
_id.value = id
_attrs.value = props.attrs
return () => h('div', {
class: `trading-vue-${id}`,
style: {
left: props.position.x + 'px',
top: props.position.y + 'px',
position: 'absolute',
}
}, [
h('canvas', Object.assign({
id: `${props.tv_id}-${id}-canvas`,
onmousemove: e => renderer.mousemove(e),
onmouseout: e => renderer.mouseout(e),
onmouseup: e => renderer.mouseup(e),
onmousedown: e => renderer.mousedown(e),
ref: 'canvas',
style: props.style,
}, props.attrs))
].concat(props.hs || []))
};
function render() {
const id = props.grid_id
const layout = props.layout.grids[id]
return () => create_canvas(h, `grid-${id}`, {
position: {
x: 0,
y: layout.offset || 0
},
attrs: {
width: layout.width,
height: layout.height,
overflow: 'hidden'
},
style: {
backgroundColor: props.colors.back
},
hs: [
h(Crosshair, Object.assign(
common_props(),
layer_events
)),
h(KeyboardListener, keyboard_events),
h(UxLayer, {
id,
tv_id: props.tv_id,
uxs: uxs.value,
colors: props.colors,
config: props.config,
updater: Math.random(),
onCustomEvent: emit_ux_event
})
].concat(get_overlays(h))
})
};
render()
}
}
This doesn't seem to return anything in my template. I think that i'm not calling the render function in the right way. Can anyone help me understanding how to use it?
As per my understanding, h() is a short form to create the vnodes and accept 3 parameters.
h(
tag name,
props/attributes,
array of children
)
As per my understanding, In create_canvas you are trying to create a div which contains a class and inline styles as a props/attributes and we are creating a canvas as a children of this div vnode. Hence, Instead of returning the vNode directly from setup(), it should return a render function that returns a vNode.
export default {
props: {
// props will come here
},
setup(props) {
// render() { h(...) } ❌
return () => {
h('div', {
class: `trading-vue-${id}`,
style: {
left: props.position.x + 'px',
top: props.position.y + 'px',
position: 'absolute',
}
}, [
h('canvas', Object.assign({
id: `${props.tv_id}-${id}-canvas`,
onmousemove: e => renderer.mousemove(e),
onmouseout: e => renderer.mouseout(e),
onmouseup: e => renderer.mouseup(e),
onmousedown: e => renderer.mousedown(e),
ref: 'canvas',
style: props.style,
}, props.attrs))
].concat(props.hs || []))
} ✅
}
}
First you are are not "calling" render function - you are just declaring it (Vue is caling it when rendering)
In Composition API you just need to return render function from setup
import { ref, h } from 'vue'
export default {
props: {
/* ... */
},
setup(props) {
const count = ref(1)
// return the render function
return () => h('div', props.msg + count.value)
}
}
After applying this knowledge on your own code I would say that the last line of setup should not be render() but return render() (because the the render() function itself returns actual "render" function)
In JS functions are treated as data - you can store them in variables and return them from the functions. When the function is stored or returned as a result of another function, it is not executed immediately - it is only created. The one who calls the "factory" function (in this case factory function is setup() and the caller is Vue) can store the reference to the returned function and decides when to call it
The Vue Composition API onMounted hook works very similarly. You are calling onMounted() passing a newly created function as an argument. onMounted stores the reference to the function somewhere so the Vue can later call it.
The point is that it does not matter that in setup() the onMounted() is executed 1st and your render function is returned as a last statement of setup. Because Vue decides when to call them "sometimes later". And it is reasonable to expect that Vue for sure will call your render function at least once before calling a function passed into onMounted() (because component cannot be mounted before it is rendered)
I have a component with a save button
<Button onClick={() => requestSaveAsync()}>Save</Button>
I also need to be able to call requestSaveAsync from the top level of the app, so I added a useImperativeHandle hook inside a custom hook called useEditRow
interface Props {
ref: MutableRefObject<{
addItem: () => void
}>
}
const useEditRow = (props: Props) => {
useImperativeHandle(props.ref, () => ({
addItem: () => requestSaveAsync()
})
}
The useEditRow hook is inside of an OrderItemTable component
const OrderItemTable = forwardRef(function OrderItemTable(props: Props, ref: MutableRefObject<any>) {
const editRow = useEditRow({
ref: ref
})
})
The requestSaveAsync method uses useMutation from react-query
useMutation(mutateFn, {
onSuccess: () => dispatch({type: 'clear', name: 'row'})
})
Clear row sets the state to initial state. If requestSaveAsync is called by clicking the button, the row is cleared. If I call it through the parent component, the onSuccess function is called, but the dispatch doesn't do anything. If I put a breakpoint on the dispatch function, I see the following code about to called from react_devtools_backend.js
useReducer: function (a, b, e) {
a = F();
b = null !== a ? a.memoizedState : void 0 !== e ? e(b) : b;
z.push({
primitive: "Reducer",
stackError: Error(),
value: b
});
// devtools show the empty function on this line will be executed next
return [b, function () {}];
},
At first I thought that maybe useImperativeHandle was using stale state, so I tried returning {...initialState} instead of initialState. This didn't seem to help. I tried adding the dependencies array suggested by react-hooks/exhaustive-dep. That didn't help. Does anyone know why when dispatch is called from useImperativeHandle, the state doesn't update?
Here is a codesandbox with some of the basic ideas that were shown abo.
Your useImperativeHandle hook doesn't appear to be using the forwarded React ref. In other words, React refs are not regular React props that can be accessed by children components.
You should use React.forwardRef to correctly forward any passed refs on to the function component.
React.forwardRef
Forwarding Refs
You didn't include your function component but if you follow the examples in the links provided it's fairly trivial to figure out.
Example:
const MyComponentWithSaveButton = (props, ref) => {
useImperativeHandle(ref, () => ({
addItem: requestSaveAsync,
}));
const requestSaveAsync = () => { .... };
...
};
export default React.forwardRef(MyComponentWithSaveButton);
Notice here the function component signature not accepts two arguments, the props object and the React ref that is being forwarded, and that the useImperativeHandle hook references the forwarded ref.
I am using Tabulator under React, with the react-tabulator module.
I am missing something very basic, likely due to my new knowledge of React. Implementing this module, I know how to connect a tabulator callback to a javascript function. But I don't know how to call a tabulator method. For instance:
const options = {
height: '100%',
ajaxURL: 'http://example.com',
ajaxProgressiveLoad: 'scroll',
ajaxError: (error) => {
console.log('ajaxError ', error);
},
};
...
<ReactTabulator
columns={columns}
layout="fitColumns"
data={[]}
options={options}
/>
Here the ajaxError callback is passed to ReactTabulator, and called when appropriate.
Now, the tabulator module has lots of methods, for instance setData. Outside of React, this would be used as follows:
var table = new Tabulator("#example-table", {
ajaxURL:"http://www.getmydata.com/now", //ajax URL
});
...
table.setData("http://www.getmydata.com/now");
How do I translate this into the React world (in a hook environment), since I don't have direct access to the equivalent of a 'table' object? Do I need to get to my tabulator object by using getElementById or something similar?
I believe that the solution is to use a ref as described here:
https://reactjs.org/docs/refs-and-the-dom.html
, in the section:
Refs and Function Components
By default, you may not use the ref attribute on function components because they don’t have instances:
...
You can, however, use the ref attribute inside a function component as long as you refer to a DOM element or a class component:
Using this approach I am able to access my tabulator setData method.
const tableDisplay = (props) => {
const tableRef = createRef();
// I can now use setData in various effects:
// if ((tableRef.current) && (tableRef.current.table)) {
// tableRef.current.table.setData();
return (
<ReactTabulator
ref={tableRef}
columns={columns}
layout="fitColumns"
data={[]}
options={options}
/>
);
};
This works just fine, I am just not sure this is the "clean" way to go about it?
You need to fetch the api from useEffect and useState its result. Heres an example
import React,{ useState, useEffect }from "react"
import { ReactTabulator } from "react-tabulator"
const Dashboard = props => {
const [data,setData] = useState([])
const getData = async () => {
const result = await fetch("http://www.getmydata.com/now") // this is where you call the api and get its result
setState(result.data) // this is where you set the result to your state
}
useEffect(()=>{
getData()
},[])
const columns=[
{
title:"name",
field:"name",
},
{
title:"Number of Request"
field:"noOfRequest",
}
]
return (
<ReactTabulator
columns={columns}
layout="fitColumns"
data={data} // here is the state of the table
options={options}
/>
)
}
export default Dashboard
This is how you get data from an api in React.
I am implementing push notifications in a react native project, where from the parent component of the application I need to pass parameters through the reactNavigation screenProps for a BottomTabNavigator. Once I receive a notification, and I change the status to update the parameter that will indicate to the child components that must be updated, a complete re-rendering of the application is made.
This is my code:
class AppLayout extends Component {
state = {
updatePushNotifications: false
}
handleActivatePushNotifications = () => {
this.handlePushNotificationMessageListener();
}
handlePushNotificationMessageListener = async () => {
this.notificationListener = firebase.notifications().onNotification((notification) => {
const { title, body } = notification;
console.log(notification);
console.log('notificationListener');
//SETSTATE FOR UPDATE CALLS IN CHILD COMPONENTS
this.setState({
updatePushNotifications: true
});
this.showAlert(title, body);
});
}
showAlert = (title, message) => {
Alert.alert(
title,
message,
[
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{cancelable: false},
);
}
// The entire navigation component is re-rendered once the setState is executed
render () {
return (
<Layout
screenProps={{
updatePushNotifications: this.state.updatePushNotifications
}}
/>
);
}
}
How can I prevent a re-render of the application when I update any of the parameters that I am passing through the screenProps?
Thanks in advance for any help
If you use state in your render method, it always re-render your app with state changes. You can define a variable in class and update it. Then pass it to prop. But be careful, because you can't see changes if you don't make forceUpdate.