I am trying to use webworker in our demo application, but I am not able to create instance of my worker. I get the error worker` is read only. Why?
Here is my code
https://codesandbox.io/s/bold-forest-s3guc?file=/src/App.js
import React, { useEffect } from "react";
import "./styles.css";
import worker from "./workerfile";
import WebWorker from "./setup";
export default function App() {
const buttonHan = () => {
alert("==g=");
};
useEffect(() => {
// worker = new WebWorker(worker);
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<button onClick={buttonHan}>BTN</button>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
The iissue is when I am creating a object of worker in useEffect in the below line.
// worker = new WebWorker(worker);
On button click, I want to send trigger to my worker for calculation.
You have two lines that are in conflict.
import worker from "./workerfile";
and
// worker = new WebWorker(worker);
You first import from a file and assign the value to a variable named worker.
You should not then later change that value. If you must use that name you can shadow-scope your variable by including a block-scope keyword such as let or const. But you can also just redefine the variable name (e.g. myWorker or similar).
The const value worker is the default export and therefore readonly. I assume you want to use the worker object for the creation of the WebWorker.
Just remove the part where you are storing the created WebWorker in the worker constant variable.
import React, { useEffect } from "react";
import "./styles.css";
import worker from "./workerfile";
import WebWorker from "./setup";
export default function App() {
const buttonHan = () => {
alert("==g=");
};
useEffect(() => {
new WebWorker(worker);
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<button onClick={buttonHan}>BTN</button>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
Related
Im new in react.
I'm Created two file App.js and UseEffect.js
I'm Learn about lifecycle in react with function.
So When I See in console, that's render multiple time.
You can see my picture below.
My Console In Browser
This Is My Code
UseEffect.js
import React, {useState, useEffect} from "react";
function MyFunction(){
console.log('-> Function Init')
const [count, setCount] = useState(0)
const handleCount = () => {
setCount(prevState => {
return prevState+1
})
}
//LifeCycle
useEffect(() => {
console.log('my first effect')
})
console.log(`-> Start Render (${count})`)
return(
<div>
<h1>Function Component</h1>
<p>
<button onClick={handleCount}>Count</button>
{count}
</p>
</div>
)}
export default MyFunction
App.Js
import './App.css';
import UseEffect from './components/UseEffect'
function App() {
return (
<div className="App">
<UseEffect />
</div>
);
}
export default App;
How do it's work?, I Want it. it's just render one times.
Your useEffect call is missing a dependency array. When you want it to run only at the initial render, you need to pass it an empty array as its dependencies.
useEffect(() => {
console.log('my first effect')
}, [])
For further details, see this question.
Why it renders twice:
It's an intentional feature of the StrictMode. This only happens in development, and helps find accidental side effects put into the render phase. We only do this for components with Hooks because those are more likely to accidentally have side effects in the wrong place.
-gaearon
TLDR: It's a feature not a bug.
When I try to save my component in React the following happens:
import React from "react";
const Product = () => {
return;
<div>
<h1>hello i'm testing</h1>
</div>;
};
export default Product;
Everytime I save my component it automatically adds a semicolon at the end of each line, even if I don't need them. Expected result would be:
import React from "react";
const Product = () => {
return
<div>
<h1>hello i'm testing</h1>
</div>
}
export default Product
This is the first time that happens to me and I don't have a clue. I'm a noob here.
could you please tell me how send data from component to worker on button click?
I tried like that not working
// xx.postMessage([first.value,second.value]);
could you please suggest where i am doing wrong .I want to do some background calculation and return result to component.
here is my code
import React, { useEffect } from "react";
import "./styles.css";
import worker from "./workerfile";
import WebWorker from "./setup";
export default function App() {
const buttonHan = () => {
alert("==g=");
// xx.postMessage([first.value,second.value]);
//console.log("Message posted to worker");
};
useEffect(() => {
let xx = new WebWorker(worker);
//xx.addEventListener("message", event => {
// });
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox1</h1>
<button onClick={buttonHan}>BTN</button>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
code
https://codesandbox.io/s/bold-forest-s3guc?file=/src/App.js:212-263
This is the way i'd do it, idk if it's the supreme right way but i haven't had any problem declaring vars like this.
Also it's extremely useful when it comes to work with third party event handlers
export default function App() {
let xx = new WebWorker(worker); // Declare worker
// Constants declarations
const buttonHan = () => {
alert("==g=");
xx.postMessage("[first.value,second.value]");
console.log("Message posted to worker");
};
useEffect(() => {
xx.addEventListener("message", event => {
console.log(event)
});
}, [xx]); // useEffect executes when worker is setted
// this should be done even if variable is not a state
...
EDIT: better explanation
The context:
I receive some plain HTML code from a 3rd server, which I want to
insert in my React app
modify it
The vanilla JS approach
I can modify the string with regex and add any HTML tag with an id
Then I can modify these elements through getElementById, as usual
The React approach
I shouldn't use the DOM
Then I should insert within the string some components that have a React ref inside
The opposite (to insert some React components as plain HTML) would be through ReactDOMServer.renderToString
So, when I inject the components with ReactDOM.render(), the problem is that the render method takes its time, so that if in the next line I try to use the ref that exists in the inserted component, is not yet there
The question
How to do it? Usually I would put the code within a useEffect with a [] dependencies, but here I am rendering the component when the app is already mounted
A quick workaround is to just do an async wait of 500 ms, and then I can access the ref, but for sure there has to be something better
This code fails, because when the ref is rendered it is still not available, so ref.current is undefined
How can I wait for it?
codesandbox
EDIT: I provide the code that works but through direct DOM, which I assume should be avoided
import React, { useRef, useEffect } from "react";
import ReactDOM from "react-dom";
export default function App() {
const myref = useRef();
useEffect(() => {
const Com = () => <div ref={myref}>hello</div>;
ReactDOM.render(<Com />, document.getElementById("container"));
console.log(myref.current); // undefined
document.getElementById('container').textContent = "direct DOM works"
// the next line fails since the ref is not yet available
// myref.current.textContent = "but this REF is not available"; // fails
}, []);
const plainhtml = '<div><div id="container"></div><div>some more content</div><div id="another">even more content</div></div>'; // this is some large HTML fetched from an external server
return (
<div>
<h1>Hello CodeSandbox</h1>
<div dangerouslySetInnerHTML={{ __html: plainhtml }} />
</div>
);
}
useEffect with empty dependency array executes after the first render, therefore you will get the DOM ref in the callback:
const htmlString = '<div id="container">Hello</div>';
export default function App() {
const myRef = useRef();
useEffect(() => {
if (myRef.current) {
myRef.current.textContent = 'whats up';
}
console.log(myRef.current);
}, []);
return (
<div>
<div ref={myRef} dangerouslySetInnerHTML={{ __html: htmlString }} />
<div dangerouslySetInnerHTML={{ __html: htmlString }} />
</div>
);
}
/* App renders:
whats up
Hello
*/
I need to use a callback ref but encapsulating it within useCallback to make sure it only rerenders with the dependencies indicated (i.e. none []), so that it is only executed when the component changes (as explained here)
codesandbox
import React, { useEffect, useCallback } from "react";
import ReactDOM from "react-dom";
export default function App() {
const measuredRef = useCallback(node => {
if (node !== null) {
node.textContent = "useCallback DOM also works";
}
}, []);
useEffect(() => {
const Com = () => <div ref={measuredRef}>hello</div>;
ReactDOM.render(<Com />, document.getElementById("container"));
document.getElementById("container").textContent = "direct DOM works";
}, []);
const plainhtml = '<div id="container"></div>';
return (
<div>
<h1>Hello CodeSandbox</h1>
<div dangerouslySetInnerHTML={{ __html: plainhtml }} />
</div>
);
}
I'm currently working on using React to upload a CSV file and convert the data to an array so I can access phone numbers. I've actually got it almost completely functional, with just one problem: I can't figure out how to store the array properly in a variable (dataDump) on the global level. It stores it inside another array.
Here's a picture of my console so you can see what I mean.
I'm able to access the contents of dataDump if I use dataDump[0] (as seen in the function for handleClick), but that won't work for a global variable. I need to be able to send the array's values to other components/files, so I don't think having to call it like that will work. Chances are I'm over-complicating this in my head and the answer is incredibly simple, but I've spent the past 2-3 weeks learning React, Twilio, Mongodb etc. from scratch so my brain's not cooperating.
I'll appreciate any help! Thanks! Code below. (Note this is a component that's imported to the App page.)
import React from "react";
import CSVReader from "react-csv-reader";
var dataDump = [];
console.log(dataDump);
const papaparseOptions = {
header: true,
dynamicTyping: true,
skipEmptyLines: true,
transformHeader: header => header.toLowerCase().replace(/\W/g, "_"),
complete: function(results) {
dataDump.push(results.data);
console.log(dataDump);
var rows = results.data;
let numbers = rows.map(a => a.phone_number); //make the results ONLY the phone numbers
// console.log(numbers);
document.getElementById("data2").innerHTML=numbers; //display the phone numbers
}
};
class Import extends React.Component {
constructor(props) {
super(props);
this.state = {data:[]};
this.handleClick = this.handleClick.bind(this);
}
handleForce = data => {
// console.log(data.length);
console.log(data);
this.setState({data: data});
};
handleClick = () => {
console.log("success");
console.log(this.state.data);
console.log("Next is Numbies:");
let numbies = dataDump[0].map(a => a.phone_number);
console.log(numbies);
document.getElementById("data").innerHTML=numbies;
}
render() {
return (
<div className="container">
<CSVReader
className="csv-input"
label="Select CSV file to import"
onFileLoaded={this.handleForce}
parserOptions={papaparseOptions}
/>
<div>
</div>
<button onClick={this.handleClick.bind(this)}>
Test
</button>
<div id="data" />
<div id="data2" />
<div id="data3">
</div>
</div>
);
}
}
export default Import;
// export default DataController;
Under the hood React-Redux is using context and hooks these days, so don't bother implementing a Redux stack until you've outgrown the simpler, React API, or at least you've fixed your issue. Folks joke that Redux is like shooting a fly with a bazooka. More info on React-Redux internals here and here's the documentation for React's Context.
Some psuedo-code to get you on the right path:
// context.js
import { createContext } from 'react';
export const Store = createContext();
// app.js
import React from 'react';
import { Store } from './context';
import Import from './import'; // I wouldn't change the casing on or reuse a reserved keyword personally, maybe calling this something like 'CsvImporter' would be an improvement
function App() {
const [dataDump, setDataDump] = React.useState([]);
return (
<Store.Provider value={{ dataDump, setDataDump }}>
<Import dataDump={dataDump} setDataDump={setDataDump} />
</Store.Provider>
);
}
Now your import component has two new props, dataDump and setDataDump. You can call setDataDump just like any other call to setting state. Nice!
So you need the dataDump in a new component? That's easy peasy, lemon squeezy, and all without global variables or tossing module scoping to the side:
// foobar.js
import React from 'react';
import { Store } from './context';
export function Foobar() {
// you probably want to do more than force render an array as a string, but this is just a proof of concept
return (
<Store.Consumer>
{({ dataDump, setDataDump }) => (
<p>
`${dataDump}`
</p>
)}
</Store.Consumer>
);
}
Just make sure that Foobar or other components are rendered as children of the Provider in app.js and now you have a 'global' context for passing around dataDumps.