Executing Functions Between Two Child Components Svelte - javascript

I'm working on an Electron project using Svelte for the frontend. I'm relatively new to Svelte. So here is the problem, I have a parent component named MainContent.svelte and two child components editor.svelte and preview.svelte. The Editor and Preview are both placed in the MainContent component. What I want to do is when the content of the Editor is changed, I want to update the Preview pane to reflect those changes. I previously had done this same project using Vanilla JavaScript but thought of using Svelte as it was easier to manage the project.
There is function which listens for any changes in the Editor pane and another function to update the Preview pane. But what I can't wrap my head around is how to call the function to update the Preview when the Editor content changes. Any help would be greatly appreciated.

I would use a property and lift the state up to the main component, you can still use functions internally if you have to, e.g.
<script>
// ...
let content = '...';
</script>
<Editor bind:content />
<Preview {content} />
If the preview needs to update via a function you can call that in a reactive statement:
<script>
// ...
export let content;
$: updatePreview(content);
</script>

Related

DOM remove method in react js

I want to change remove a certain tag with an id in the html page, eg.<div id="theid"><p>sometext</p></div> Is there any ways to do it with react js? I know I can do it with javascript by document.getElementById("theid").remove();, how can I do it in the react way? I don't need a button or anything, just simply remove it when the page loads. I'd prefer methods without importing any modules or libraries if possible. Thank you.
You should likely use a ref:
https://reactjs.org/docs/refs-and-the-dom.html
So you attach the ref to the DOM element, then you can imperatively remove that element just like you specified.
So in the component function body:
const myRef = useRef();
Then in the component render:
<Component ref={myRef} />
Then you can use the code in your question to remove the element from the DOM.
ref.remove();
If you need to do it when the page loads look at using useEffect to achieve this. Although if you're removing an element on page load, I question why you even need the element there in the first place ;).
If it's rendered as part of React, the right way to do it would be to simply omit it from the source code:
const App = () => (
<div>
<div id="theid">foo</div>
<div>more content</div>
</div>
);
to
const App = () => (
<div>
<div>more content</div>
</div>
);
If it's not part of React, then remove it from whatever process generates the HTML.
If that's not an option - if it must be part of the HTML served to the client and it's not rendered as part of React - then you'll have to resort to doing what you're currently doing:
document.getElementById("theid").remove();
probably completely separate from your React script, since it's something you want to do only once, when the page loads, and not something that needs to be a part of the React lifecycles.

Change in HTML attribute of web component not reflected in Vue component

I'm facing the below problem.
I have a pure web component:
<my-web-comp options='["op1", "op2"]' active-option="op2"></my-web-comp>
This renders as two tabs with the second one selected by default. When you click on the other, the active-option HTML attribute changes to op1 and you can actually see that the property is changing in the DOM if you open the DevTools.
However, I cannot detect the change in the Vue component where I am using the web component. I have:
<template>
<div>
<my-web-comp :options="options" :active-option="activeOption"></my-web-comp>
</div>
</template>
<script>
export default {
name: 'MyVueComponent',
data() {
return {
options: '["op1", "op2"]',
activeOption: "op2"
}
},
computed: {
testVar() {
console.log("activeOption", this.activeOption) <--------- THIS LINE
},
}
}
</script>
The marked line only gets fired on the first load of the Vue component (printing "op2"). After that, testVar never gets modified again, doesn't mind if I click on the other tab and I don't see nothing in the console.
What can I be missing? I think it can be something related with Vue reactivity system, but can't wonder what.
This happens because your web-component mutates copy not a reference of this variable (copy created by your web component is also not reactive). There are two ways to change this:
You can modify your web component to use getters and setters to change value of this variable
You can use MutationObserver. To detect changes in your web-component. This approach will not require changes in this web-component
If you choose approach with MutationObserver then create this observer in vue mounted life-cycle-hook

I'm trying to render a react component on DOM node, defined in a pug file

Background Information
The basic structure of my initial application was
main.pug
... code elements ...
<div class = "panel">
... code elements ...
and a starter javascript file that is loaded in the header, which contains this block of code
starter.js
document.addEventListener('DOMContentLoaded', function() {
... logic to determine html page to show in the panel div ...
... it determines the name and saves it in the variable 'htmlPageToShow' ...
$(".panel").load(htmlPageToShow);
});
this bit of code in starter.js is how content is displayed in the panel div
it determines the file name and then loads it into the dom element
Problem
I decided that i wanted to have React handle this part, my conclusion was to render a React component called into the panel div, in hopes of improving this bit of the code without having to change the entire code base but two days in, and I cannot get a react component, or html element of any kind, to render in the div, similar to how html pages were loaded
My attempts
I left the main.pug file alone and in starter.js, did this:
starter.js
import react from 'react';
import ReactDom from 'react-dom';
import PanelHandler from './PanelHandler';
ReactDom.render(
<PanelHandler/>,
document.getElementById('panel'));
I've tried multiple versions of this, such as replacing the get element id bit with $(".panel") I've tried using getElementByClassName, QuerySelector, I've tried using window.document
I've also tried putting the whole thing into a script tag and appending it to the end of main.pug
At some point, I tried creating a new html page, with the code above in a script tag, and then loading that into panel, with the previous logic, all to no avail
I want to know if I'm missing something, can pug just not be used with React? am I missing a dependency? any help at all would be appreciated!

react js trigger function from any other component

I have a component that basically loads a video in an overlay using JW Player (simplified example below).
import React, { Component } from 'react'
import ReactJWPlayer from 'react-jw-player'
class VideoPopup extends Component {
render() {
return (
<div id="video">
<ReactJWPlayer
playerId='video-player'
playerScript='https://content.jwplatform.com/libraries/vr6ybmGf.js'
file='path to video file'
/>
</div>
)
}
}
export default VideoPopup;
I would like the component to sit directly in the root of my app, but I need to be able to display it when called from ANY other component - this might be a child component, a child of a child, a sibling etc. etc. I was hoping to be able to call it and pass the video file reference simply like below:
<button onClick={somehow show video popup}>show video popup</button>
I understand how to do this easily if there is a direct parent-child relationship, but not if I want to place the link in a variety of different components; I hope someone can point me in the right direction.
If you want to get rid of the parent-children relationships when it comes to actions, use an event manager like Redux (react-redux). It is pretty standard an becomes necessary as your app grows anyway.
The principle is that wherever you place your link, it will fire an "action" on click, which is sent to a global dispatcher that other components listen to for changes.
Multiple ways to do this
You can define a function that controls the show/hide functionality
of the video player in the app component itself and pass it down as a
prop to all the components where the event can be fired.
Use Redux. This is the ideal choice. You just have to dispatch an action from anywhere in your app and the corresponding reducer will take care of the functionality.
Using a global function (not recommended).
Please comment if you need more explanation.
You can try to make global function and call it wherever you want.
showVideoPopup () {
ReactDOM.render(
<VideoPopup />,
document.getElementById('popupHolder')
);
}

Pass reference of a component to another one in ReactJS

Before anyone press eagerly the close button, I already have looked the following question: ReactJS Two components communicating. My problem is exactly the third scenario developped in the current accepted answer.
I am using ReactJS to build something with two components. For HTML reasons (and presentation), i want my two components to be at two different places of the page.
For the moment, I have the following pattern, corresponding to scenario #2:
FooForm = React.createClass({
...
});
FooList = React.createClass({
...
});
FooManager = React.createClass({
...
render: function () {
return (
<div>
<FooForm ref="form" manager={this} />
<FooList ref="list" />
</div>
);
}
});
React.render(
<FooManager someProp={value} />,
document.getElementById('foo')
);
This gives something like:
<div id="foo">
<form>Form generated with the render of FooForm</form>
<ul>List generated with the render of FooList</ul>
</div>
However, i would like to have something like this:
<div id="fooform">
<form>Form generated with the render of FooForm</form>
</div>
<!-- Some HTML + other controls. Whatever I want in fact -->
<div>...</div>
<div id="foolist">
<ul>List generated with the render of FooList</ul>
</div>
The problem here is: how can I keep a reference in each component? Or at least the link Form -> List?
I tried to create the FooList before and pass the reference to the current manager, but I get the following warning/error:
Error: Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's `render` method). Try rendering this component inside of a new top-level component which will hold the ref.
The documentation says you can attach events to link two components which do not have a parent-child relation. But I don't see how. Can someone give me some pointers?
The Less Simple Communication lesson from react-training has a good example of how you can move actions & state sideways to avoid having to create an explicit link between related components.
You don't need to jump into a full Flux implementation to get the benefit of this approach, but it's a good example to lead you up to Flux, should you eventually need it or something like it.
Note that this requires you to model the relationship between the components based on changing state rather than explicitly passing a reference to a component instance (as you're doing above) or a callback bound to the component managing the state.
This would be the perfect use-case for a Flux type architecture.
What you want is someone FooManager to be able to trigger state changes in both components. Or, in fact, having the different components trigger, through Actions, state changes in each other.
The Flux Todo-App Tutorial illustrates your use-case perfectly!
After this, then you'd have the choices of using Facebooks implementation of Flux or the other gazillion ones.
My personal favorite is Reflux

Categories

Resources