Is that possible to call react component from outside?
For example
HTML
<div id='react-app'></div>
<button onClick=callReactModal()>PressME</button>
My component where i want call method
let callReactModal = function () {
console.log('clicked');
//Navigation.sayHello();
}
class Navigation extends React.Component<any, any> {
constructor(props:any){
super(props);
this.state = {
language: {
lang: cookie.load('lang') || ''
}
};
this.click = this.click.bind(this);
}
sayHello = () => {
alert("Hello");
}
}
I have to call Modal from another component but i don't know how to achieve that.
Trying to call method which update state in class and getting Warning: setState(...): Can only update a mounted or mounting component. It needs to open modal ( Using semantic-ui )
method which uses state
handleOpen = (e) => this.setState({
modalOpen: true,
})
modalPart
<Modal size='small'
open={this.state.modalOpen}
onClose={this.handleClose}
trigger={<a className="btn btn-base" onClick={this.handleOpen}>Login</a>}
closeIcon='close'>
Thanks for help!
Although not the best practice. You have to set callReactModal function in the window
window.callReactModal = function () {
console.log('clicked');
//Navigation.sayHello();
}
A better way to implement it, is to create an event listener that opens the modal when triggered.
No, it's not possible. All your "custom tags"(React Components) should be inside your JSXs. But you can render multiple React apps per page if you want:
<div id='react-app'></div>
<div id='react-button'></div>
Related
I have created a toggle button which will show and hide the value variable. But I can't see the changes on the screen, Although console shows the value of 'show' is changing every time I click the 'Change Me' button.
import React from 'react'
export default function State(){
let val = 4;
let show = true;
function changeMe(){
show = !show;
console.log(show);
}
return(
<div>
{show ? <span>{val}</span> : null}
<br></br>
<button onClick = {changeMe}>Change Me</button>
</div>
)
}
What I understand about functional component is that they are stateless component and we can only present the state/props of them. Is this is the reason I can't create toggle button without hooks to render the changes. Please correct me If I am wrong or add on your answer/thought to clear my concept.
PS: I am new to React and learning concepts of React. So, it might be a silly question.
What I understand about functional component is that they are stateless component and we can only present the state/props of them. Is this is the reason I can't create toggle button without hooks to render the changes.
Yes. If you don't use hooks, function components are stateless. To have a stateful component, either:
Use hooks, or
Use a class component instead
Note that function components can have props without using hooks (and usually do). Props are basically state the parent element manages. The parent can even pass your function component a function it calls in response to an event that may make the parent component change the prop the function component uses (using state in the parent, via hooks or a class component). But props are distinct from state.
For instance, here's a function component with a ticks property updated by the parent:
const {Component, useState, useEffect} = React;
function Child({ticks}) {
return <div>{ticks}</div>;
}
class ClassParent extends Component {
constructor(props) {
super(props);
this.state = {
ticks: 0
};
this.onTick = this.onTick.bind(this);
}
componentDidMount() {
this.timer = setInterval(this.onTick, this.props.interval || 1000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
onTick() {
this.setState(({ticks}) => {
++ticks;
return {ticks};
});
}
render() {
return <Child ticks={this.state.ticks} />;
}
}
function FunctionParent({interval = 1000}) {
const [ticks, setTicks] = useState(0);
useEffect(() => {
const timer = setInterval(() =>{
setTicks(t => t + 1);
}, interval);
}, []);
return <Child ticks={ticks} />;
}
function Example() {
return <div>
<ClassParent interval={800} />
<FunctionParent interval={400} />
</div>;
}
ReactDOM.render(<Example/>, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
I very new to testing and I am currently testing React components with jest/enzyme.
I have a parent component
ParentComp.jsx
export class ParentComp extends React.Component {
super(props);
this.state = {
selectedTemplate: "",
disabled: true
};
return <Modal
header={<h2>Header</h2>}
visible={true}
footer={<span>
<Button
disabled={false}
onClick={ () => {
sessionStorage.setItem('id', this.state.id);
}}
>
Continue
</Button>
}>
<h1> My modal </h1>
</Modal>
}
How would I go about testing the onClick and making sure the sessionStorage is tested?
I've already tried:
ParentComp.spec.jsx
const wrapper = shallow(<ParentComp/>);
wrapper.find(Modal).first().props().footer.find(Button).simulate('click')
jest.spyOn(window.localStorage.__proto__, 'setItem');
window.localStorage.__proto__.setItem = jest.fn();
// assertions as usual:
expect(localStorage.setItem).toHaveBeenCalled();
expect(global.sessionStorage.getItem).toBecalledWith('id',1)
}
I thankfully don't get any actual errors, however, my sessionStorage line in ParentComp is apparently not being covered. How would I go about covering this line?
I have an idea to call directly prop onClick directly in this case instead of simulating of click. As long as you can find your <Button /> in your footer then call its prop of onClick. Let's try:
// You can console.log to see what is the correct to select the right one
// I'm not sure below route is correct :)
const yourButton = wrapper.find(Modal).first().props().footer.props.children;
yourButton.props.onClick();
I am having a react-app where i am rendering button in one component and model in another component . The button access the function openModal for opening the modal through refs. i am writing test cases for my application but could not figure out a way to write a test case for checking the modal is opening on button click
Buttons component
<div>
<button type='primary' onClick={() => this.handleClick.showModal()}>
ADD
</button>
<AddConceptModal ref={(instance) => this.handleClick = instance}/>
</div>
Modal component:
class ModalComp extends React.Component {
state = {
visible: false,
}
// show modal handles the logic of opening the modal
showModal = () => {
this.setState({
visible: true,
})
}
render() {
const { visible } = this.state
return (
<div>
<Modal
visible={visible}
>
modal
</Modal>
</div>
)
}
}
export default ModalComp
i tried creating instance like this:
let component = mount(<ModalComp />)
const instance = component.instance()
i even tried spyOn method in jest could do it exactly. how can i write test that simulate the button in button component which calls the showModal() and
i want to check if modal is receiving prop as true after button click simulation
I want to use the 'compare' button to toggle the compare state to true or false.
Next I want to pass this compare state to pivot as props.
I am literally using the same code as in the react documentation when looking at the Toggle class. https://facebook.github.io/react/docs/handling-events.html
The only thing I changed is the name isToggleOn to compare.
When looking at the console client side I get following error every time the component renders:
modules.js?hash=5bd264489058b9a37cb27e36f529f99e13f95b78:3941 Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.`
My code is following:
class Dashboard extends Component {
constructor(props) {
super(props);
this.state = { compare: true };
this.handleClick = this.handleClick.bind(this);
}
handleClick(button) {
if (button === 'compare') {
this.setState(prevState => ({
compare: !prevState.compare,
}));
}
}
render() {
return (
<Grid>
<div className="starter-template">
<h1>This is the dashboard page.</h1>
<p className="lead">
Use this document as a way to quickly start any new project.<br />{' '}
All you get is this text and a mostly barebones HTML document.
</p>
</div>
<ButtonToolbar>
<button onClick={this.handleClick('compare')}>
{this.state.compare ? 'AGGREGATE' : 'COMPARE'}
</button>
</ButtonToolbar>
<PivotTable
ready={this.props.isReady}
data={this.props.gapData}
compare={this.state.compare}
/>
</Grid>
);
}
}
export default (DashboardContainer = createContainer(() => {
// Do all your reactive data access in this method.
// Note that this subscription will get cleaned up when your component is unmounted
const handle = Meteor.subscribe('weekly-dashboard');
return {
isReady: handle.ready(),
gapData: WeeklyDashboard.find({}).fetch(),
};
}, Dashboard));
Any advice on how to fix this?
The reason is this line
<button onClick={this.handleClick('compare')}>
This will call the handleClick function while executing render function. You can fix by:
<button onClick={() => this.handleClick('compare')}>
Or
const handleBtnClick = () => this.handleClick('compare');
...
<button onClick={this.handleBtnClick}>
...
I prefer the latter
Say I have a component (header.jsx) which has a button. When that button is clicked I want to open a Dialog that I created with Material UI. This dialog component is in another file I called dialog.jsx. I know how I could do it all in one file: simply create a function that is linked to the button and calls a show event on the dialog tag. However if I were to separate these two into components in separate files, how can I accomplish this?
you can user ReactDom.render method for rendering a component on a particular action
suppose I have dialog.jsx like
var Dialog=React.createClass({
//render function goes here
});
module.exports=Dialog
I want to use this component on button click then your parent component should be like
var parent=React.createClass({
click:function()
{
ReactDom.render(<Dialog />,document.getElementById("child");
},
render:function()
{
return(
<div>
<div id="child">
<div>
<button onClick={this.click} />
</div>
)
}
});
hope this may help you
Do it like this....
var React = import('react'),
Dialog = require("path.to.dialog.jsx"),
header = React.createClass({
componentWillReceiveProps: function(){
this.setState({"showDialog" : false});
},
onButtonClick : function(){
this.setState({"showDialog" : true});
},
render: function(){
return (
<div>
<Your other layout>
<Button text="Open dialog" click={this.onButtonClick} />
</Your other layout>
<Dialog show={this.state.showDialog} />
</div>
);
}
});
You can accomplish what you're trying to do by passing a ref prop to the Dialog component. You then can call methods on the Dialog component by reference to the this.refs object inside the Parent component. Here's a CodePen showing this in action. http://codepen.io/anon/pen/pgNVpa Obviously, the code in CodePen is all in one file. Below is how you would do it in multiple files.
Now, just because you can do this doesn't mean you should. I would recommend the approach #HaZardouS took in his answer. That's the classic React pattern. In the React docs, they caution against overuse of refs.
https://facebook.github.io/react/docs/more-about-refs.html
If you have not programmed several apps with React, your first
inclination is usually going to be to try to use refs to "make things
happen" in your app. If this is the case, take a moment and think more
critically about where state should be owned in the component
hierarchy. Often, it becomes clear that the proper place to "own" that
state is at a higher level in the hierarchy. Placing the state there
often eliminates any desire to use refs to "make things happen" –
instead, the data flow will usually accomplish your goal.
Dialog.jsx
class Dialog extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
open: false
};
this.open = this.open.bind(this);
this.close = this.close.bind(this);
}
open() {
this.setState({
open: true
});
}
close() {
this.setState({
open: false
});
}
render() {
if (this.state.open) return <p>Dialog is open.</p>;
else return <p>Dialog is closed.</p>
}
}
export default Dialog;
Parent.jsx
import Dialog from './Dialog';
class Parent extends React.Component {
constructor(props, context) {
super(props, context);
this.openDialog = this.openDialog.bind(this);
this.closeDialog = this.closeDialog.bind(this);
}
openDialog() {
this.refs.dialog.open();
}
closeDialog() {
this.refs.dialog.close();
}
render() {
return (
<div>
<button onClick={this.openDialog}>Open Dialog</button>
<button onClick={this.closeDialog}>Close Dialog</button>
<Dialog ref="dialog" />
</div>
);
}
}
React.render(<Parent />, document.querySelector('#react-app'));