react component is undefined under <Popup></Popup> - javascript

SOLVED:
Thank you all for helping. I realized in the library I used, the trigger={} is a pre-defined tool that seems only works with a button. I wrote my own Popup component instead and fixed the problem.
I am working on a group project, and I want to make a popup window. I installed reactjs-popup. The code below works:
import UsernameForm from "./UsernameForm";
function RoomContainer() {
// ...
return (
// ...
<div>
<UsernameForm
inputtedUsername={inputtedUsername}
setInputtedUsername={setInputtedUsername}
/>
</div>
);
}
But, once I wrap <UsernameForm /> under <Popup></Popup> like below:
import UsernameForm from "./UsernameForm";
import Popup from "reactjs-popup";
function RoomContainer() {
//...
return (
<div>
{/* ... */}
<Popup trigger={/* something to trigger the pop up window */}>
<UsernameForm
inputtedUsername={inputtedUsername}
setInputtedUsername={setInputtedUsername}
/>
</Popup>
</div>
);
}
I got an error message saying:
React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports."
I tried to add {} on the import, didn't work.

Make sure that a proper pop up trigger has been set.
<Popup trigger={<button>Trigger</button>} position="right center">
<UsernameForm
inputtedUsername={inputtedUsername}
setInputtedUsername={setInputtedUsername}
/>
</Popup>

Related

Dropdown button inside Alert component in react

I've been searching how to embed a dropdown button inside the Alert component antd. I took it simple, just to add a button inside the Alert such as is shown in the documentation:
However, when copying the same code in my React project, the button is not present in the alert and no errors shown in the console. The code looks like this:
UserAlert.js:
export const UserAlert = () => (
<>
<Alert
message="Success Tips"
type="success"
showIcon
action={
<Button size="small" type="text">
UNDO
</Button>
}
closable
/>
<Alert
message="Error Text"
showIcon
description="Error Description Error Description Error Description Error Description"
type="error"
action={
<Button size="small" danger>
Detail
</Button>
}
/>
</>
);
which is invoked from a parent component called UserSummary.js:
export class UserSummary extends Component {
render() {
return (
<UserAlert/>
)};
}
export default UserSummary;
The previous code is not failing, but showing like this:
Am I missing something? Should I try in different way?
Thanks a lot for you attention and help.
I tried to reproduce it, but for me the button appears. And one thing that's wrong in your snippet is the name of the Alert component. It's called MineAlert, but in the UserSummary, you use UserAlert. I think it's just a typo?
I tried it here:
https://codesandbox.io/embed/vigorous-rain-j6y1oj?fontsize=14&hidenavigation=1&theme=dark
Maybe some information about the imports and styling you use would be helpful. Would be great if you could share a bit more context.

Why is dangerouslySetInnerHTML property returning Uncaught Invariant Violation error?

I am trying to build a simple markdown previewer using react and marked.js. Feel like I am almost there - I can console.log the markdown, but for some reason I get an error when trying to insert the HTML. Here is the code:
//import { useState } from 'react';
const {useState} = React
//MAIN APP
function App(){
const [text, setText]=useState("Test")
function editorHandler(event){
setText(event.target.value)
}
return(
<div>
<h1> MARKDOWN PREVIEWER </h1>
<Editor onChange={editorHandler} markDown={text}/>
<Preview previewText={text}/>
</div>
)
}
ReactDOM.render(<App/>, document.getElementById("App"))
// EDITOR COMPONENT
function Editor(props){
return(
<div className="window">
<h2>editor</h2>
<textarea id="editor" value={props.markDown} onChange={props.onChange} placeHolder="Write something here"> </textarea>
</div>
)
}
// PREVIEW COMPONENT
function Preview(props){
console.log(marked(props.previewText)) // works, outputs: <p>Test</p>
function getMarkDownText() {
const rawMarkup = marked(props.previewText)
return {__html: rawMarkup};
}
return(
<div className="window">
<h2>previewer</h2>
<div id="preview" dangerouslySetInnerHTML={getMarkDownText()}> </div>
</div>
)
}
The problem seems to be with that last div (id preview). I get the following error message which is not very helpful: "Uncaught Invariant Violation: Minified React error #60"
Codepen is here if easier: https://codepen.io/rpollock03/pen/RwWvYQb?editors=1011
Grateful for an explanation of what I'm doing wrong. I am learning React so apologies if this is something silly! I've tried reading the docs - the marked.js ones weren't very clear in my opinion.
Replace
<div id="preview" dangerouslySetInnerHTML={getMarkDownText()}> </div>
with
<div id="preview" dangerouslySetInnerHTML={getMarkDownText()} />
This will solve it.
Codepen uses minified react-dom (react-dom.production.min.js). Hence you are not clearly seeing the error. In the minified production build of React, they avoid sending down full error messages in order to reduce the number of bytes sent over the wire.
But if you open browser console, you will find the following message
Invariant Violation: Minified React error #60; visit
https://reactjs.org/docs/error-decoder.html?invariant=60 for the full
message or use the non-minified dev environment for full errors and
additional helpful warnings.
And once you go to the link in above message, you will get actual error, which is
Can only set one of children or props.dangerouslySetInnerHTML.
As children are not allowed (and also not required) when dangerouslySetInnerHTML is used, to solve this issue, we removed the children by replacing <div> </div> with <div/>

load image as prop in react-native

so I have a customHeader component where I am trying to load images into like so
<Image source={props.logoImg} style={styles.icon} />
and on the page I'll pass in the prop like so
<CustomHeader
navigation={props.navigation} //call props.navigation in component
primaryColor={primaryColor}
coName={coName}
logoImg={require('../content/...some image...'}
/>
This way it doesn't throw an error, but it doesn't load. I know it has something to do with passing it as a prop because I can load images straight into the screens. I'm just not sure what I'm doing wrong or what I'm missing here.
I have tried using the require inside of the component, but that throws an error at compile because react-native needs the images to be "required" at compile.
this should work
in the Wrapping component
<CustomHeader
imageUri={'../content/...some image...'}
/>
and then in the inner component
<Image source={require(props.imageUri)} />

Warning: Failed prop type: Invalid prop `children` supplied to `j`

I am getting this error:
index.js:1375 Warning: Failed prop type: Invalid prop children supplied to j.
in j (at HomePage.jsx:15)
in HomePage (created by Context.Consumer)
in Route (at App.jsx:17)
in App (at src/index.js:13)
in Router (created by BrowserRouter)
in BrowserRouter (at src/index.js:12)
I am using an external component in my app which i got from github which renders a video in the background. Here is the link for that.
https://github.com/samAbeywickrama/reactjs-videobg
It's something related to proptypes but since its legacy and react suggests to use flo, I am not using type check at all.
import React from "react";
import {
Container,
Header,
Image,
Button,
Icon
} from "semantic-ui-react";
import VideoBg from 'reactjs-videobg';
import mp4 from '../../video/hack4.mp4';
const HomePage = ({history}) => {
return (
<div className='masthead'>
<VideoBg loop={true}>
<VideoBg.Source src={mp4} type='video/mp4' />
</VideoBg>
<Container text textAlign='center'>
<Header as='h1' inverted>
<Image
size='massive'
src='/assets/logo.png'
alt='logo'
style={{ marginBottom: 12 }}
/>
CodeUp
</Header>
<Button onClick={() => history.push('/events')} size='huge'
inverted>
Enter
<Icon name='right arrow' inverted />
</Button>
</Container>
</div>
);
};
children is a prop used within the VideoBg component to add the video source to it.
I've raised an issue on the lib repo to investigate further
This should be a comment but need more reputation for that...
I sometimes find it really tricky to debug react. There doesn't seem to be anything called j in your code
I do see one thing in this code - doesn't work, you needtext={true} , see above
jsx tag attributes are really jsx (Javascript) objects, so it can't deal with something like text. So you have to give it a hint that it is a boolean
This may or may not be the problem....

How can I use Enzyme React Test .find method?

I am trying to learn Enzyme + Jest testings in React components and I'm having an error in using .find method in Enzyme.
Error
Method “simulate” is meant to be run on 1 node. 0 found instead.
19 | onAddNew={onAddNew} />);
20 |
> 21 | component.find('button.btn-primary').simulate('click');
| ^
22 | expect(onAddNew).toHaveBeenCalledTimes(1);
I checked the rendered html and I can see the button and class name exactly as I wrote in the find method.
According to this link, I can write the Enzyme selector as div.className. I thought we can write Enzyme selectors as JQuery selectors. So, I used button.btn-primary or button.btn btn-primary, but it doesn't work.
However, if I used .find('Button') it can find it. It shows an error that, it found 2 nodes because I have 2 Buttons in the component. Does it mean that .find method performs the search on React Components rather than rendered DOM document? If yes, how can I write the selector to find the Primary button? Is there a way to find it without using first() or (0)?
Please see the following codes as detail:
workoutAdd.test.js
import React from 'react';
import { shallow } from 'enzyme';
import WorkoutAdd from '../workoutAdd';
it('renders without crashing', () => {
const
onChange = jest.fn(),
onChangeDate = jest.fn(),
onAddNew = jest.fn(),
toggle = jest.fn(),
item = {};
const component = shallow(<WorkoutAdd
toggle={toggle}
modal={true}
item={item}
onChange={onChange}
onChangeDate={onChangeDate}
onAddNew={onAddNew} />);
component.find('button.btn-primary').simulate('click');
expect(onAddNew).toHaveBeenCalledTimes(1);
});
Component - workoutAdd.js
import React, { Component } from 'react';
import {
Modal, ModalBody, ModalHeader, ModalFooter, Button
, Form, FormGroup, Label, Input
} from 'reactstrap';
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
export default class WorkoutAdd extends Component {
render() {
const {
modal,
toggle,
item,
onChange,
onChangeDate,
onAddNew } = this.props;
return (
<Modal isOpen={modal} toggle={toggle} centered>
<ModalHeader toggle={toggle}>Add New Workout</ModalHeader>
<ModalBody>
<Form>
<FormGroup>
<Label for="Date">Date</Label><br />
<DatePicker
name="date"
id="Date"
className="form-control"
selected={item.date}
onChange={onChangeDate}
dateFormat="dd/MM/yyyy"
maxDate={new Date()}
/>
</FormGroup>
<FormGroup>
<Label for="WorkoutType">Type</Label>
<Input
type="select"
name="workoutType"
onChange={onChange}
value={item.workoutType}
id="WorkoutType">
<option>Running</option>
<option>Cycling</option>
</Input>
</FormGroup>
<FormGroup>
<Label for="Calories">Calories</Label>
<Input
type="number"
name="calories"
id="Calories"
value={item.calories}
onChange={onChange}
placeholder="Calories burnt"
/>
</FormGroup>
</Form>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={onAddNew}>Save</Button>{' '}
<Button color="secondary" onClick={toggle}>Cancel</Button>
</ModalFooter>
</Modal>
)
}
}
UPDATED Answers
The code I used in the question (button.btn-primary) doesn't work because I'm using Bootstrap component to render Button. If you are using traditional button html to render your button, it will work.
There are many ways to achieve this requirement.
Method 1
console.log(component.debug()); is the key utility to analyze how Enzyme renders and sees the component.
component.find("Button").at(0).simulate('click') as mentioned by Matt.
However, you cannot move the position of the buttons / add new buttons and the test will fail.
Method 2
component.find('Button[color="primary"]').simulate('click');
or
component.find('Button').find({ color: 'primary' }).simulate('click');
You can use the above codes to find the right button with any attribute/prop. By using these, your test codes do not couple to the implementation of the component. You do not need to worry about the position of the button anymore. Having said that, if you have 2 buttons with 'primary', you will need to find out another way to identify the button uniquely.
Since you're only shallow mounting, it would be Button.btn-primary or Button.btn.btn-primary. You can confirm this by writing console.log(component.debug()); inside of your it test, and it'll print out the DOM structure as enzyme sees it.
If you want, you can also generalize your .find() to component.find("Button").at(0).simulate('click') or in layman's terms "find a Button component at position 0 and simulate a click". Or simply component.find(".btn-primary").simulate('click'). You have many options to find a DOM element and it becomes a personal preference (although, I'd much prefer a more specific selector, especially if you ever mount a component).
As a side note, be care about generalized imports:
import WorkoutAdd from '../workoutAdd'; can resolve to workAdd.test.js instead of workoutAdd.js if they're within the same folder. So if you ever run into issues where jest states expected a string (for built-in components) or a class/function (for composite components), then you'll know why.

Categories