Return vue component from a function - vue.js

I'm new to Vue and I would want to render an SVG icon depending on task status and would like to create a re-usable function for that, How can I do that?
In React I could have done something like this:
const iconStatusMapping = {
todo: <svg></svg>,
processing: <svg>...</svg>,
done: <svg>...</svg>
}
// utils.ts
export const getTaskStatusIcon = (status: TaskStatus) => {
return iconStatusMapping[status]
}
function App() {
const status = "todo"
return (
<div>{getTaskStatusIcon(status)} {status}</div>
)
}
How can I do something similar in Vue3?

In React, it may be not a good idea to define reused elements as JSX that is not wrapped in a function because element objects are expected to be new on every render. This may have no consequences for SVG icons but may have unexpected behaviour in other cases.
In Vue, this snippet could be directly translated to render function and JSX.
Static HTML like SVG icons can be safely defined as strings and outputted with Vue v-html, the same applies to React dangerouslySetInnerHTML:
const iconStatusMapping = {
todo: `<svg></svg>`,
...
}
and
v-html="iconStatusMapping[status]"

Related

Nuxt3 "Never define ref() outside of <script setup>", then how?

from nuxt 3 documentation,
https://nuxt.com/docs/getting-started/state-management
I'm told that I should never define ref outside script setup
since it will "be shared across all users visiting your website and can lead to memory leaks!"
I want to use vueuse's useBreakpoints,
https://vueuse.org/core/useBreakpoints/
I simply put them in composable and export,
and happily use them all across components.
but I see their type is globalThis.Ref
is it safe to use them as is,
or am I in big trouble as nuxt doc says?
// file: composables/useMedia.ts
import { breakpointsTailwind, useBreakpoints } from '#vueuse/core'
const breakpoints = useBreakpoints(breakpointsTailwind)
export const isDesktop = breakpoints.greaterOrEqual('lg')
export const isTablet = breakpoints.greaterOrEqual('sm') && breakpoints.smaller('lg')
export const isMobile = breakpoints.smaller('sm')
this is closely related to vue's response system
you don't need to worry about memory leaks when using compiler tools like nuxi
however here another problem is that react system cannot determine the dependencies and when to unmount. if you want to declare once and use globally use pinia otherwise use this code:
import { breakpointsTailwind, useBreakpoints } from '#vueuse/core'
export function useMedia() {
const breakpoints = useBreakpoints(breakpointsTailwind)
const isDesktop = breakpoints.greaterOrEqual('lg')
const isTablet = breakpoints.greaterOrEqual('sm') && breakpoints.smaller('lg')
const isMobile = breakpoints.smaller('sm')
return { isDesktop, isTable, isMobile }
}
and use
const { isDesktop } = useMedia()
note: your code doesn't react when changing the values. if you need response use computed

how am I breaking rules of hook? [duplicate]

In this example, I have this react class:
class MyDiv extends React.component
constructor(){
this.state={sampleState:'hello world'}
}
render(){
return <div>{this.state.sampleState}
}
}
The question is if I can add React hooks to this. I understand that React-Hooks is alternative to React Class style. But if I wish to slowly migrate into React hooks, can I add useful hooks into Classes?
High order components are how we have been doing this type of thing until hooks came along. You can write a simple high order component wrapper for your hook.
function withMyHook(Component) {
return function WrappedComponent(props) {
const myHookValue = useMyHook();
return <Component {...props} myHookValue={myHookValue} />;
}
}
While this isn't truly using a hook directly from a class component, this will at least allow you to use the logic of your hook from a class component, without refactoring.
class MyComponent extends React.Component {
render(){
const myHookValue = this.props.myHookValue;
return <div>{myHookValue}</div>;
}
}
export default withMyHook(MyComponent);
Class components don't support hooks -
According to the Hooks-FAQ:
You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.
As other answers already explain, hooks API was designed to provide function components with functionality that currently is available only in class components. Hooks aren't supposed to used in class components.
Class components can be written to make easier a migration to function components.
With a single state:
class MyDiv extends Component {
state = {sampleState: 'hello world'};
render(){
const { state } = this;
const setState = state => this.setState(state);
return <div onClick={() => setState({sampleState: 1})}>{state.sampleState}</div>;
}
}
is converted to
const MyDiv = () => {
const [state, setState] = useState({sampleState: 'hello world'});
return <div onClick={() => setState({sampleState: 1})}>{state.sampleState}</div>;
}
Notice that useState state setter doesn't merge state properties automatically, this should be covered with setState(prevState => ({ ...prevState, foo: 1 }));
With multiple states:
class MyDiv extends Component {
state = {sampleState: 'hello world'};
render(){
const { sampleState } = this.state;
const setSampleState = sampleState => this.setState({ sampleState });
return <div onClick={() => setSampleState(1)}>{sampleState}</div>;
}
}
is converted to
const MyDiv = () => {
const [sampleState, setSampleState] = useState('hello world');
return <div onClick={() => setSampleState(1)}>{sampleState}</div>;
}
Complementing Joel Cox's good answer
Render Props also enable the usage of Hooks inside class components, if more flexibility is needed:
class MyDiv extends React.Component {
render() {
return (
<HookWrapper
// pass state/props from inside of MyDiv to Hook
someProp={42}
// process Hook return value
render={hookValue => <div>Hello World! {hookValue}</div>}
/>
);
}
}
function HookWrapper({ someProp, render }) {
const hookValue = useCustomHook(someProp);
return render(hookValue);
}
For side effect Hooks without return value:
function HookWrapper({ someProp }) {
useCustomHook(someProp);
return null;
}
// ... usage
<HookWrapper someProp={42} />
Source: React Training
you can achieve this by generic High order components
HOC
import React from 'react';
const withHook = (Component, useHook, hookName = 'hookvalue') => {
return function WrappedComponent(props) {
const hookValue = useHook();
return <Component {...props} {...{[hookName]: hookValue}} />;
};
};
export default withHook;
Usage
class MyComponent extends React.Component {
render(){
const myUseHookValue = this.props.myUseHookValue;
return <div>{myUseHookValue}</div>;
}
}
export default withHook(MyComponent, useHook, 'myUseHookValue');
Hooks are not meant to be used for classes but rather functions. If you wish to use hooks, you can start by writing new code as functional components with hooks
According to React FAQs
You can’t use Hooks inside of a class component, but you can
definitely mix classes and function components with Hooks in a single
tree. Whether a component is a class or a function that uses Hooks is
an implementation detail of that component. In the longer term, we
expect Hooks to be the primary way people write React components.
const MyDiv = () => {
const [sampleState, setState] = useState('hello world');
render(){
return <div>{sampleState}</div>
}
}
You can use the react-universal-hooks library. It lets you use the "useXXX" functions within the render function of class-components.
It's worked great for me so far. The only issue is that since it doesn't use the official hooks, the values don't show react-devtools.
To get around this, I created an equivalent by wrapping the hooks, and having them store their data (using object-mutation to prevent re-renders) on component.state.hookValues. (you can access the component by auto-wrapping the component render functions, to run set currentCompBeingRendered = this)
For more info on this issue (and details on the workaround), see here: https://github.com/salvoravida/react-universal-hooks/issues/7
Stateful components or containers or class-based components ever support the functions of React Hooks, so we don't need to React Hooks in Stateful components just in stateless components.
Some additional informations
What are React Hooks?
So what are hooks? Well hooks are a new way or offer us a new way of writing our components.
Thus far, of course we have functional and class-based components, right? Functional components receive props and you return some JSX code that should be rendered to the screen.
They are great for presentation, so for rendering the UI part, not so much about the business logic and they are typically focused on one or a few purposes per component.
Class-based components on the other hand also will receive props but they also have this internal state. Therefore class-based components are the components which actually hold the majority of our business logic, so with business logic, I mean things like we make an HTTP request and we need to handle the response and to change the internal state of the app or maybe even without HTTP. A user fills out the form and we want to show this somewhere on the screen, we need state for this, we need class-based components for this and therefore we also typically use class based components to orchestrate our other components and pass our state down as props to functional components for example.
Now one problem we have with this separation, with all the benefits it adds but one problem we have is that converting from one component form to the other is annoying. It's not really difficult but it is annoying.
If you ever found yourself in a situation where you needed to convert a functional component into a class-based one, it's a lot of typing and a lot of typing of always the same things, so it's annoying.
A bigger problem in quotation marks is that lifecycle hooks can be hard to use right.
Obviously, it's not hard to add componentDidMount and execute some code in there but knowing which lifecycle hook to use, when and how to use it correctly, that can be challenging especially in more complex applications and anyways, wouldn't it be nice if we had one way of creating components and that super component could then handle both state and side effects like HTTP requests and also render the user interface?
Well, this is exactly what hooks are all about. Hooks give us a new way of creating functional components and that is important.
React Hooks let you use react features and lifecycle without writing a class.
It's like the equivalent version of the class component with much smaller and readable form factor. You should migrate to React hooks because it's fun to write it.
But you can't write react hooks inside a class component, as it's introduced for functional component.
This can be easily converted to :
class MyDiv extends React.component
constructor(){
this.state={sampleState:'hello world'}
}
render(){
return <div>{this.state.sampleState}
}
}
const MyDiv = () => {
const [sampleState, setSampleState] = useState('hello world');
return <div>{sampleState}</div>
}
It won't be possible with your existing class components. You'll have to convert your class component into a functional component and then do something on the lines of -
function MyDiv() {
const [sampleState, setSampleState] = useState('hello world');
return (
<div>{sampleState}</div>
)
}
For me React.createRef() was helpful.
ex.:
constructor(props) {
super(props);
this.myRef = React.createRef();
}
...
<FunctionComponent ref={this.myRef} />
Origin post here.
I've made a library for this. React Hookable Component.
Usage is very simple. Replace extends Component or extends PureComponent with extends HookableComponent or extends HookablePureComponent. You can then use hooks in the render() method.
import { HookableComponent } from 'react-hookable-component';
// πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡
class ComponentThatUsesHook extends HookableComponent<Props, State> {
render() {
// πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡
const value = useSomeHook();
return <span>The value is {value}</span>;
}
}
if you didn't need to change your class component then create another functional component and do hook stuff and import it to class component
Doesn't work anymore in modern React Versions. Took me forever, but finally resulted going back to go ol' callbacks. Only thing that worked for me, all other's threw the know React Hook Call (outside functional component) error.
Non-React or React Context:
class WhateverClass {
private xyzHook: (XyzHookContextI) | undefined
public setHookAccessor (xyzHook: XyzHookContextI): void {
this.xyzHook = xyzHook
}
executeHook (): void {
const hookResult = this.xyzHook?.specificHookFunction()
...
}
}
export const Whatever = new WhateverClass() // singleton
Your hook (or your wrapper for an external Hook)
export interface XyzHookContextI {
specificHookFunction: () => Promise<string>
}
const XyzHookContext = createContext<XyzHookContextI>(undefined as any)
export function useXyzHook (): XyzHookContextI {
return useContext(XyzHookContextI)
}
export function XyzHook (props: PropsWithChildren<{}>): JSX.Element | null {
async function specificHookFunction (): Promise<void> {
...
}
const context: XyzHookContextI = {
specificHookFunction
}
// and here comes the magic in wiring that hook up with the non function component context via callback
Whatever.setHookAccessor(context)
return (
< XyzHookContext.Provider value={context}>
{props.children}
</XyzHookContext.Provider>
)
}
Voila, now you can use ANY react code (via hook) from any other context (class components, vanilla-js, …)!
(…hope I didn't make to many name change mistakes :P)
Yes, but not directly.
Try react-iifc, more details in its readme.
https://github.com/EnixCoda/react-iifc
Try with-component-hooks:
https://github.com/bplok20010/with-component-hooks
import withComponentHooks from 'with-component-hooks';
class MyComponent extends React.Component {
render(){
const props = this.props;
const [counter, set] = React.useState(0);
//TODO...
}
}
export default withComponentHooks(MyComponent)
2.Try react-iifc: https://github.com/EnixCoda/react-iifc

how to call a function in other component in react-native

I'm working on a board game, which uses a long code to generate data to the board.
Currently I have 2 components. Home and Board. Home only has a Welcome message and a button to navigate into Board.
Currently Board has the function to generate the data, but I'd like to move this function to other component, generate the data there and return an array to my Board component. This new function/component won't do anything else but return an array to Board.
Is it possible to do in React-Native? I'm coming from other programming logic, and I cannot figure out how to achieve this.
Thank you.
you can use props in React Native, this link for documentation and this for passing function in props to component
Use ref.
Class A extends React.Component{
returnArray = () => return ['a','b','c'];
render(){....}
};
In other class
Class B extends React.Component{
getArray = () => {
const array = this.comp.returnArray(); //do whatever you want to do with the array
}
render(){
return <A ref={ref=>this.comp=ref}/>
}
}
In the function component you can export you function like:
export const arrayFunction = () => {
// array generation code
return array
}
and in your board component you can import the function from js file and use it like this.
const array = arrayFunction()
this constant array will have the array returned from the function.
Perhaps my best suggestion is that you need to use redux for the management of functions and states on several components and can be used anywhere (global) for the documentation, it can be seen clearly enough at:Reudux Official

React Native: How can I use the DeviceInfo isTablet() method to conditionally apply a style to an element?

I am trying to adapt the design of my app to tablet and one way to detect if the app is running on a tablet is by using the DeviceInfo module in particular the isTablet() method. How can I use this method to conditionally apply styles to an element?
Here is what I am trying to do at the moment:
import { checkIfDeviceIsTablet } from './helper-functions';
<View style={[styles.wrapper, checkIfDeviceIsTablet() === true ? styles.wrapperTablet : {}]}>
{contents}
</View>
The checkIfDeviceIsTablet() function is as follows:
import DeviceInfo from 'react-native-device-info';
function checkIfDeviceIsTablet() {
DeviceInfo.isTablet().then(isTablet => {
return isTablet;
});
}
The issue is that when the component loads the checkIfDeviceIsTablet() method returns a promise as opposed to the expected true/false value and so the conditional styles are not applied when the app is run on a tablet. I tried turning the function into an async/await format with a try/catch but the result is the same.
I would use React Native's own Platform.isPad function but the app must also work on Android.
Any help is appreciated.
I would recommend calling DeviceInfo.isTablet() only once at the beginning of your app. You can store the result globally, and then later on you can check the type without having to deal with async promises.
To store the type globally, your options are:
A global variable
React's Context API
A static property on a class (if using ES6+)
Some sort of global state management solution like Redux
You still have to deal with the initial async problem, since the first call to DeviceInfo.isTablet() will return an async promise.
I'd recommend looking into React's Context API.
Here's a rough example:
render() {
return (
<DeviceInfoContext.Consumer>
{ ({ isTablet }) => (
<Text>Is this a tablet? {isTablet}</Text>
) }
</DeviceInfoContext.Consumer>
)
}
And your DeviceInfoContext class would look something like this:
class DeviceInfoContext extends React.Component {
state = {
isTablet: false
}
componentDidMount() {
Device.IsTablet().then(result => this.setState({ isTablet: result }))
}
render() {
return (
this.props.children({ isTablet: this.state.isTablet })
)
}
}
This is just a rough example. You can learn more about the Context API in the docs
Me too had some troubles with the breaking changes of react native 0.5xx to 0.6xx. The library for device detection change it structure to promises. A paintful.
This library save the day, the installation and use is very easy.
https://github.com/m0ngr31/react-native-device-detection
import { isTablet } from 'react-native-device-detection;
// isTablet is a boolean. Return false o true immediately
//So ...
import styled from 'styled-components/native';
import theme from 'styled-theming';
import { isTablet } from 'react-native-device-detection';
const CoverPageDateText = styled.Text`
font-size: ${isTablet ? 23 : 17};
color: gray;
padding-bottom: 9;
`

Vue's render createElement gives error when passed a regular Vue file

So I created a Vue file with a render function that is supposed to loop over IDs and create components according to those.
Specifically inside my render function I'm using createElement to which I pass three params:
A Vue component (from a JS file)
a config object
A Vue component (from a Vue file)
It's 3. that's giving me this error:
Failed to mount component: template or render function not defined.
this Vue file has no render function, but it does have a template, so I'm confused why this error is happening.
In the code below [createElement([dialogs[id]])] is the part that gives the error:
import { QDialog } from 'quasar'
import Signin from './Signin.vue'
import Signout from './Signout.vue'
const dialogs = {
Signin,
Signout
}
function createDialogNode (id, createElement, parent) {
return createElement(QDialog, {
props: {
value: parent.toggles[id]
},
on: {
input: function (newState) {
parent.toggles[id] = newState
}
}
}, [createElement([dialogs[id]])])
}
// further down I use `createDialogNode` inside the render function and loop over the props inside `dialogs`.
So in the code above you see I have an object dialogs with imported components. These components are regular Vue files.
I want to pass them inside createElement as third param to the other createElement that is returned in my function above.
You can't pass an array to createElement as the first argument.
Try this instead:
createElement(dialogs[id])