Sharing props with composition API - javascript

Is there any way to share props between components using the composition API, or should I still resort to mixins for that?
For example, I have a "visible" prop that I want to reuse on 5 components. How can I define it in 1 common place and reuse it with the composition API?
With a mixin I would have done it the old fashioned way:
const mixin = {
props: { visibile: { type: Boolean: required: false } }
}
Used in the component:
mixins: [theMixinAbove]
How can I accomplish this using the composition API?

You can do it, but I think you'll need to implement props as-well in a similar manner, and you can't do it during setup because at that point, the props are already expected.
For example you can define a function that lives with your other function you would use during setup, and then destructure it into the rest of your props
props:{myInternalProp:String, ...withVisibilityProps()},
const app = Vue.createApp({})
app.component('my-component', {
template: '<h1>My Component is {{visiblity}}</h1>',
props:{...withVisibilityProps()},
setup(props){
return({...withVisibility(props)})
}
})
function withVisibility(props) {
return {visiblity:Vue.ref(props.visible?"visible":"not visible")};
}
function withVisibilityProps() {
return {visible:Boolean};
}
app.mount('#app')
<script src="https://unpkg.com/vue#3.0.4/dist/vue.global.prod.js"></script>
<div id="app">
<my-component :visible="true"></my-component>
<my-component :visible="false"></my-component>
</div>
note that the setup function is used to handle the visibility variable. If you only need the prop, you can skip the withVisibility and setup

You can use script setup and use defineProps inside the composable.
https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits

Related

Is there a way to access slot in Svelte component created using Client-side component API?

I am creating a svelte component in use:action function and I need to get add dynamic content inside the component. Does svelte allow to replace slot during or after creation of a svelte component?
Example code
export default function (node: HTMLElement) {
let component = new Component({
props: {},
target: node,
// maybe this
slot: anotherComponent,
});
// or this
component.slot = anotherComponent;
return {
update() {},
destroy() {
component.$destroy();
},
};
}
That is currently not supported, though that is a popular feature request. As noted in the issue, you can use private APIs at the peril of them breaking at any point.
You might be able to work around this by exposing an element of the component and mounting the child component there.

Vue 3 Composition API data() function

Reading the composition api documentation for Vue 3, I didn't quite understand how the new Composition API works. Could you please explain where the data() function has gone? And if it is no longer used what to use instead?
Updated 23.10.2021: The documentation in the link has been updated and expanded to include a mention of the data() in the Composition API introduction, so this question is now deprecated.
Under the new Composition API, all of the variables that you previously defined in data() are just returned from your setup() function as normal variables with reactive values. For example, a Vue 2.0 component that had a data function like so:
data() {
return {
foo: 1,
bar: { name: "hi" }
}
}
becomes this setup() function in Vue 3:
setup() {
const foo = ref(1);
const bar = reactive({ name: "hi" });
return { foo, bar }
}
The ref helper wraps a non-object value for reactivity, and reactive wraps an object. This is exposing the underlying principles of Vue more clearly than the old way, where the wrapping happened "magically" behind the scenes, but will behave the same otherwise. What I like about it personally is that your setup() function can build up your object on the go while keeping related things together, allowing it to tell a cohesive story and not require jumping around to different sections.
The composition is the new feature comes with Vue 3 and as a plugin for Vue 2, it doesn't replace the old option api but they could be used together in the same component.
The composition api compared to option api :
Gather the logic functionalities into reusable pieces of logic.
Use one option which the setup function which is executed before the component is created, once the props are resolved, and serves as the entry point for composition API's.
Define your old data option as ref or reactive properties
computed and watch is defined as : watch(...,()=>{...}) or computed(()=>{...})
Methods defined as plain javascript functions.
setup option used instead of created hook and it has as parameters the props and context
Hooks like mounted could be used as onMounted(()=>{...}), learn more
With script setup syntax you could declare your reactive data using ref, reactive and computed ...
<script setup >
import { ref, reactive, computed } from 'vue'
const isActive = ref(false)
const user = reactive({ firstName: 'John', lastName: 'Doe', age: 25 })
const fullName = computed(() => user.firstName + ' ' + user.lastName)
</script>

How do I call a mixin function from another component?

MyMixin.vue has the method beginEdit.
What I'm trying to do is to make onFirstLineClick to call myMixin's beginEdit depending on the value of this.folded.
When I console logged myMixin.beginEdit, it is undefined and not surprisingly myMixin.beginEdit() doesn't work.
Am I missing something needed to use the function? If so, why does beginEdit work perfectly on <span>?
<template>
<div>
<div>
<div
#click="onFirstLineClick"
/>
<span
#click="beginEdit"
/>
</div>
</template>
<script>
import myMixin from './MyMixin';
export default {
name: 'currComponent',
mixins: [myMixin],
data() {
return {
folded: false,
};
},
methods: {
onFirstLineClick(e) {
// myMixin.beginEdit() doesn't work
}
},
};
</script>
The great thing about mixin is that when a component uses a mixin, all options in the mixin will be "mixed" into the component's own options. Which means that inside your component you can call mixin method directly like:
methods: {
onFirstLineClick(e) {
this.beginEdit()
}
},
That is also the reason why you can use beginEdit() method on <span> directly like:
<span #click="beginEdit" />
Please also know that in future if you declare a method in this component with same name as mixin method name beginEdit, then the component's method will take priority and you might see different behaviour. So, make sure to give unique names to mixin methods.

What's the purpose of using classes in React?

I mostly see JavaScript use classes as a constructor as following:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}
What's the reason React uses classes without using the contructor() function, such as following? I don't see classes being used to create instances.
class App extends Component {
render() {
return (
<div className="app-content">
</div>
)
}
}
Right now you should use classes in React if you need to use "advanced" component lifecycle methods like shouldComponentUpdate() or such.
Previously class components were used to handle local state in them. Right now we have Hooks API which allows to use state in a more elegant way and without need of class components.
If you want more details, you can read the article by Dan Abramov: How Are Function Components Different from Classes?.
Regardless your example, you're right, this code:
class App extends Component {
render() {
return (
<div className="app-content">
</div>
)
}
}
can be written as:
function App() {
return <div className="app-content"></div>
}
What's the reason React uses classes without using the contructor() function
From the JavaScript class doc:
If you do not specify a constructor method, a default constructor is used.
So a constructor exists for every class whether a constructor method is specified or not.
I don't see classes being used to create instances.
React components implemented as classes get instantiated by React as part of the rendering process.
Specifically, in the new React Fiber creating an instance of a React class component happens on this line of the source code.
But yes, #vicondin is right that the simple component from the question can be implemented as a function component, that class components used to be the only way to maintain state, implement lifecycle methods, etc., and that the new Hooks makes it possible to...
use state and other React features without writing a class.
In React, state is used in a React class component. There you can set initial state in the constructor of the class, but also access and update it with this.state and this.setState, because you have access to the class instance by using the this object.
If you use class in React component, even without using constructor() you can set initial state like below:
class App extends Component {
state = {
hello: 'Hello'
};
onClickHello = value => {
this.setState({ hello: 'Why did you clicked?' });
};
render() {
return (
<div className="app-content" onClick={this.onClickHello}>
{this.state.hello}
</div>
)
}
}
Another advantage is you can make use of all the React lifecycle methods
Update: After React16, you can use the lifecycle events even in function components using react hooks
Also biggest reason is the handling of state and lifecycle(componendDidMount ..etc) , class can do everything functions can , but at the cost of readability and statelessness . But in the most cases I rarely use classes only if I need a complex parent component with lifecycle

What is the proper convention for binding the context of many React component methods in constructor()?

I have a lot of methods in my top-level React component that I want to use as callbacks in its children components. I understand that in ES6 I must manually bind the context of each method. My current constructor method looks something like this:
this.method1 = this.method1.bind(this);
this.method2 = this.method2.bind(this);
this.method3 = this.method3.bind(this);
...
This works; all of my children are able to retain the intended context whenever they invoke their callbacks but it seems like a lot of code to write for something I did not even need to write in ES5. Is there a quick way to bind context to all of my component methods without having to write all of this boilerplate?
I understand that in ES6 I must manually bind the context of each method.
Yeah, except that's not entirely true. ES6 allows you to express things a lot better than you could in ES5.
Writing your code in ES6 doesn't mean you directly translate the code you have from ES5. There's more idiomatic ways to do it using new features in current versions of React and features that are native to ES6.
import {Component} from 'react'
class Foo extends Component {
// this class doesn't even need constructor
createButton(text) {
// don't write
// return <button onclick={this.handleClick.bind(this)}>{text}</button>
// instead write
return <button onclick={e=> this.handleClick(e)}>{text}</button>
}
handleClick(event) {
console.log(event, 'button was clicked')
}
render() {
var {buttons} = this.props;
// don't write
// return <div>{buttons.map(this.createButton.bind(this)}</div>
// instead write
return <div>{buttons.map(this.createButton, this)}</div>
}
}
export default Foo;
// <Foo buttons={["one", "two", "three"]} />
Notice I used context in two different ways that didn't require Function.prototype.bind
Arrow functions have a lexical this therefore a binding isn't required in most scenarios. Arrow functions are new to ES6.
Array.prototype functions like map,reduce,forEach accept a thisArgument which allows you to change the context of the callback. This is not new to ES6, so there's nothing stopping you from using this in your ES5 code today.
But do you also see this is a stateless functional component? Stateless functional components are available as of React 0.14
In idiomatic React code, most of the components you write will be stateless, simply composing other components. We’re introducing a new, simpler syntax for these components where you can take props as an argument and return the element you want to render
source: React Blog v0.14
This code is functionally identical to the component above but requires no class or context ceremony
const createButton = (text) => {
return <button onClick={handleClick}>{text}</button>
}
const handleClick = (event) => {
console.log(event, 'button was clicked')
}
// stateless functional component
const Foo = ({buttons}) => {
return <div>{buttons.map(createButton)}</div>
}
export default Foo;
Of course this approach cannot work for components that involve state (or life cycle methods), but it works for any Components that just use props - which is most of your components.
It's just one more technique you have to write React apps in an idiomatic way that doesn't involve Function.prototype.bind.
For what it's worth, I haven't relied upon Function.prototype.bind (with code I've written) in years.
If you are using Babel, you can enable stage 0 and use the :: this binding operator.
You should be able to bind to the parent context when passing to the children:
method1() {
...
}
render() {
return <ChildComponent method1={::this.method1} />;
}
https://babeljs.io/docs/plugins/preset-stage-0/
http://babeljs.io/docs/plugins/transform-function-bind/
There are various valid approaches here; the one I prefer is to use the #autobind decorator:
import autobind from 'autobind-decorator';
class MyComponent extends React.Component {
#autobind
method1() {
// "this" is bound correctly
}
}
This requires the autobind-decorator module (or core-decorators, which exposes a similar function), plus babel-preset-decorators-legacy.

Categories