In my react app I have a component which was exported using react-redux connect.
class Test extends Component {
...
}
export default connect(...)(Test)
and using component:
<div>
<Test />
</div>
As long as I was exporting it in the same file everything was working fine. Because of tests issue I moved the connect to different file. Now it's like:
(Test.js)
class Test extends Component {
...
}
export default Test
and in different file (TestConnect.js):
import Test from './Test'
...
export default connect(...)(Test)
and using component:
<div>
<TestConnect />
</div>
As long as I had the Component and its connect in the same file changing props was rerendering the Test component. Now it's not. Could You please help me understanding that? How can I fix this?
Edit
Solved by use {pure:false} as "options" in connect!
Unless you're actually facing an edge case and this is the only way out, as stated in redux's troubleshooting section, using {pure: false} isn't the best solution, since redux expects your components to be pure (Always produce the same results, given the same props and states)
Here's how I'd do it:
Test.js
class Test extends Component {
...
render() { ... }
}
export default Test
TestContainer.js
import Test from './Test'
import connect from 'react-redux'
class TestContainer extends Component {
render() {
return(<Test {...this.props} /> (Don't forget to pass your props down, otherwise, Test won't work properly)
}
}
TestContainer = connect(...)(Test)
export default TestContainer
App.js
import TestContainer from './TestContainer'
class App extends Component {
...
render(){
return(
<div>
<TestContainer {...props (If you need to pass anything that isn't at redux store)} />
</div>
)
}
}
I've used this approach quite a few times in some projects and it's worked pretty well
If you're not in that edge case scenario and this solution still doesn't work, need some more information to see where things are going wrong :)
Related
I have a catalago-component.js which is a web component. I'm trying to use this web component like so:
import React from 'react'
import './../../../assets/catalago-component'
class Loja extends React.Component{
constructor(props){
super(props)
this.state = {}
}
render(){
return(
<React.Fragment>
<div className="page-header">
<h1 className="page-title">Loja</h1>
</div>
<catalago-component></catalago-component>
</React.Fragment>
)
}
}
export default Loja
but every time I run my react app I get this error
src\assets\catalago-component.js
Line 1:1: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:85: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:399: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:599: Expected an assignment or function call and instead saw an expression no-unused-expressions
...
but if I do any changes to the app that makes it recompile then it works just fine
how to solve this error forever? I don't want this app breaking every time I run it for the first time
EDIT: I tried to use this web component with pure html and it worked. take a look
https://eduardopreuss.github.io/web-component/
https://github.com/eduardopreuss/web-component
EDIT 2: link to codesandbox using react + web component https://codesandbox.io/s/hopeful-cohen-ut6mv?file=/src/App.js
I think you might want to try something like this:
import Catalago from './../../../assets/catalago-component'
Then use the component like:
<Catalago></Catalago>
Assuming your Web component issomething like this:
class Catalago extends React.Component {
render() {
return <speical-web-stuff><speical-web-stuff>
}
}
See:https://reactjs.org/docs/web-components.html
As said above, you should give your component a name in order to import.
import Catalago from './../../../assets/catalago-component'
However, sth you may pay attention to.
Below syntax expect your component is written in index.js under the folder catalago-component
import Catalago from './assets/catalago-component' //component locate in file name ```index```
import Catalago from './assets/catalago-component/customizedName.js'
which type of export used in that component
import Catalago from './assets/catalago-component/customizedName.js' // exporting via ```export default``` keyword
import { Catalago } from './assets/catalago-component/customizedName.js' //exporting via ```export``` keyword
Inside your webpack.config.js add this line
Than you can use your component from anywhere inside project.
import Catalago from 'Components'
There is nothing wrong how I imported, it was a eslint error just like #tsecheukfung01 said in the comments. So I added my web component to .eslintignore file and It worked just fine.
more ways to ignore eslint errors here
The way you import your component is perfectly fine.
A web-component is nothing more than any other HTMLElement like a <div> or an <a>, meaning this is NOT a React component and cannot be imported and used as such.
Example web-component
export class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `My Webcomponent!`
}
static get tag() {
return 'my-component';
}
}
customElements.define(MyComponent.tag, MyComponent);
Using the above web-component would look something like:
import './../../../assets/MyComponent.js'
...
render() {
return() {
<div>
<my-component></my-component>
</div>
}
}
import Catalago from './../../../assets/catalago-component'
...
render() {
return() {
<div>
<Catalago //other props/>
</div>
}
}
I'm trying something that I thought would be very basic but for some reason its just not working at all!
I'm simply trying to create 2 simple react components in 2 different jsx files and import one of them to the parent file and then use and render the child component in the parent one.
I have created a simple mvc site that simply goes to the index page that imports the selected jsx file which the first component is in. Reactjs is installed via nuget package manager. I'm still learning reactjs so I'm probably doing something glaringly wrong for this to not work.
I have tried using requires and es6 import/export but neither seem to work for me.
specifically using the import/export methods throws a syntax error even though I have both node.js and typescript installed in visual studio!
Any help would be great.
Please see code below:
Component1.jsx:
import Component2 from "./Component2.jsx"
class Component1 extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div>hello</div>
</div>
);
}
}
ReactDOM.render(
<Component1 />,
document.getElementById('test')
);
Component2.jsx:
class Component2 extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>test</div>
);
}
}
export default Component2;
I have a very basic program of react with tsx, I am getting an error which I am not able to figure out why
import React from 'react';
// import {connect} from 'react-redux'
export class Home extends React.Component {
render(){
console.log(this.props)
return (
<div>Working</div>
)
}
}
import * as React from 'react'
import * as ReactDOM from 'react-dom';
import {Home} from './Components/Home.component'
class App extends React.Component<any,any>{
render(){
return(
<Home value="abc" />
)
}
}
ReactDOM.render( <App />, window.document.getElementById("app"))
git clone this for code
After pulling down your repo and inspecting it, I realised that you do not have react typings for typescript.
Typings is the simple way to manage and install TypeScript definitions
Adding this line
"#types/react": "^16.0.25" // or another version you prefer
to the package.json and running npm i or yarn if you are using yarn as a package manager, one more time, solved the issue.
Try it out and let me know if this solves it on your side :)
PS: TypeScript requires you to describe the shape of your objects and your data. If you look at the other answer I provided earlier, it was pretty much a long and complicated version of You need to specify a type that describes your props and need to pass this to the component in question
Typescript needs to know the shape of the props and state passed to a component. If you really want to stop Typescript from enforcing typings in your component (which, btw, defeats the whole purpose of using Typescript), then, the component that needs access to the props or state passed to it has to specify the type or shape so to speak, as any. That is, your component will look something like this
export class Home extends React.Component<any, any>
instead of
export class Home extends React.Component
which btw, is an incorrect way of extending a class if that class expects props and/or state.
Passing any type for props and state means that the component in question must accept any kind of shape (type) for both props and state.
Try this
import * as React from "react";
import * as ReactDOM from 'react-dom';
export class Home extends React.Component<any, any> {
render() {
console.log(this.props)
return (
<div>Working</div>
)
}
}
class App extends React.Component{
render() {
return (
<Home value="abc" />
)
}
}
ReactDOM.render(<App />, document.getElementById("app"));
and everything should work as expected because you got Typescript out of your way in terms of type-checking for you.
You can also view the demo here
If you actually wanted to enforce the shape (type) of the props and/or state you would then have to define these shapes with, usually, an interface or inline type annotation. Here is an example of the same code above that enforces the shape of the props using the former method:
import * as React from "react";
import { render } from "react-dom";
interface Props {
value:string,
name:string
}
export default class Home extends React.Component<Props>{
render() {
console.log(this.props)
return (
<div>Working. The props values are: {this.props.value} {this.props.name}</div>
)
}
}
class App extends React.Component {
render() {
return (
<Home value="abc" name="def"/>
)
}
}
render(<App />, document.getElementById("root"));
Now, here you could never be able to add any other prop to the Home component that is not defined in the Props interface.
For example doing something like:
<Home value="abc" name="DEF" somethin="else"/>
would not compile because somethin is not defined in the interface that is used by the Home component.
To enforce the shape of the state you'd have to do the same thing as for the props, i.e. define a contract (interface).
Also, note that you still need to access your props via this NOT Props as this is just a type definition of the structure not holder of the values themselves.
You can view the demo for this alternative here
In reference this coding pattern:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Thing from '../components/Thing';
class ThingContainer extends Component {
render() {
return <Thing {...this.props} />;
}
}
function mapStateToProps(state) {
...
}
export default connect(mapStateToProps)(ThingContainer);
So it 1) imports a component(Thing), 2) creates another component (ThingContainer which is technically not a container) class to render that first component, and lastly using connect to finally export the container.
What's the difference with skipping step 2 above, and simply using the imported component(Thing) directly to export the container?
Yeah, that file looks like it's somewhat unnecessary. The class ThingContainer component does nothing but forward props to <Thing>, which is exactly what the wrapper components generated by connect do already. So, that's useless - the file should just do export default connect(mapState)(Thing), and it would work exactly the same without the extra ThingContainer definition.
I have a redux reducer loaded with several reactjs components.
I want to load these inside other components through this.props
Like: this.props.components.MyReactComponent
class OtherComponent extends Component {
render() {
const Component = this.props.components.MyReactComponent
return (
<div>
<Component />
</div>
)
}
}
Is this possible? If so, how?
EDIT The component is a connected component. I am able to load it but it is broken. In this case, it is a counter, when you click to increment or decrement nothing happens. In the console, there is this error:
Uncaught ReferenceError: _classCallCheck is not defined
if I convert the component into a dumb component (without connecting it), the error is this:
Uncaught ReferenceError: _classCallCheck3 is not defined
EDIT 2
I found out why those errors show up. It is because the react component gets stripped out when stored in the reducer:
A react component would look something like this:
{ function:
{ [Function: Connect]
displayName: 'Connect(Counter)',
WrappedComponent: { [Function: Counter] propTypes: [Object] },
contextTypes: { store: [Object] },
propTypes: { store: [Object] } } }
However, after I store it inside a reducer, it loses its properties and ends up looking something like this:
{ function:
{ [Function: Connect] } }
After reading the comments below, I thought of an alternative. I can store in a reducer the path to each component, then make a new wrapper component that could render those other components from those paths.
I tried it but encoutered a different problem with the funcion require from nodejs that for some weird reason is not letting me user a variable as an argument. For example:
This works:
var SomeContent = require('../extensions/myContent/containers')
This does not:
var testpath = '../extensions/myContent/containers'
var SomeContent = require(testpath)
Giving me the following error:
Uncaught Error: Cannot find module '../extensions/myContent/containers'.
It is adding a period at the end of the path. How can I prevent require to add that period?
If you can think of any other alternative I can implement for what I am trying to do, I would greatly appreciate it.
EDIT 3 Following Thomas advice...
What I am trying to accomplish is this:
I want to be able to render react components inside other react components, I know how to do it the same way most us know how to; however, I want to be able to do it by importing a file that would contain all the components without actually having to import and export each one of them:
OtherComponent.js
import React, { Component } from 'react'
import { SomeComponent } from '../allComponentes/index.js'
export default class OtherComponent extends Component {
render() {
return (
<SomeComponent />
)
}
}
SomeComponent.js
import React, { Component } from 'react'
export default class SomeComponent extends Component {
render() {
return (
<div>
Hello
</div>
)
}
}
allComponents/index.js
import SomeComponent from '../allComponents/SomeComponent/index.js'
export { SomeComponent }
What I am trying to do in allComponents/index.js is to avoid having import/export statements for each component by reading (with fs module) all the components inside the allComponents folder and export them.
allComponents/index.js (pseudocode)
get all folders inside allComponents folder
loop through each folder and require the components
store each component inside an object
export object
When I tried that, I encountered multiple issues, for one, export statements have to be in the top-level, and second, fs would work only on the server side.
So, that is why I thought of loading all the components in a reducer and then pass them as props. But as I found out, they got stripped out when stored them in a reducer.
Then, I thought of only storing the path to those components inside a reducer and have a wrapper component that would use that path to require the needed component. This method almost worked out but the nodejs function require wont allow me to pass a variable as an argument (as shown in EDIT 2)
I think your question is not really to do with redux but rather is (as you say):
What I am trying to do in allComponents/index.js is to avoid having import/export statements for each component by reading (with fs module) all the components inside the allComponents folder and export them.
By way of example, I have all of my (dumb) form components in a folder path components/form-components and the index.js looks something like:
export FieldSet from './FieldSet'
export Input from './Input'
export Label from './Label'
export Submit from './Submit'
export Select from './Select'
export Textarea from './Textarea'
Then when I want to import a component elsewhere, it is import { FieldSet, Label, Input, Submit } from '../../components/form-components/';