Force React component that have not mounted to DOM render? - javascript

I have a class that's a component of React. How can I force that class render and return to me a DOM element?
For example:
class MyComponent extends React.Component{...}
const myVirtualDOMComponentButNotMountToAnywhere = <MyComponent {...someprops} />
// is there any function that
const myDOMElement = MyComponent.createDOMElement();
// or
const myDOMElement = myVirtualDOMComponentButNotMountToAnywhere.renderAsDOMElement();
// return a result that similar to
document.createElement(...);
I want to get that DOM element to perform custom mount (or what ever I want to) to that DOM element as the result from my function I expect that similar to the result of document.createElement().
For another example as a real usecase:
import { Link } from 'react-router-dom';
const myLink = <Link to='/...' />
const myDOMLink = myLink.renderAsDOMElement();
document.getElementById('someId').appendChild(myDOMLink);

I may was too overthinking. It was provided as an API of react-dom: render
import ReactDOM from 'react-dom';
ReactDOM.render(<MyComponent />, document.getElementById('someId'))

Related

call react component-element as variable

Is it possible to call a React component element with a variable inside?
import React from "react"
/*React functional component*/
function someName() {
const someVar = "componentName"; //the name of the called component
return(
<{someVar}/>
)
}
export default someName;
I try to implement this in a router and to change the filenames(Sites) (in the element) dynamically with useState from fetched data.
I am open to all kind of help :)
There is no direct way to do that but you can use this approach.
import ComponentA from '...path';
import ComponentB from '...path';
...
const components = {
componentA: ComponentA,
componentB: ComponentB,
...
}
...
function App(props) {
const TargetComponent = components[props.componentName];
return <TargetComponent />;
}

Accessing React component state from MDX

Assume that I have the following files.
import React, { useState } from 'react';
import someComputation from './someComputation';
type ComponentType = {
input: number;
};
const Component = (props: ComponentType) => {
const [state, setState] = useState(someComputation(props.input));
console.log(state.color); // "#440000" for example
return <>...some component UI</>;
};
export default Component;
import Component from "./Component"
# Title
## Header
Body text like this
<Component input={5} />
I want to refer to the {state.color} of the component above. How?
I think one way could be update the global or a context with the value of state and then create another component that just fetch the context value.
Is there a better (easier) way to achieve this?

React conditional style on custom click

I am trying to change a class when onClick event is fired, my function is called and it seems to be working but the class just won't update un the render, this is my code:
import React from 'react';
const Something = props => {
let opened = false;
const toggle = () => {
opened = !opened;
};
return (
<div className={opened ? 'some-class opened' : 'some-class'}>
<div className="some-inner-class" onClick={toggle}>
...content
</div>
</div>
);
};
export default Something;
I just want to be able to change style on when click event is fired.
My suggestion to you will be to use react hooks in this scenario, by that I mean, something like this, I have updated your code with my suggestion;
Hope it helps;
import React, { useState } from 'react';
const Something = props => {
// ***because this doesn't exist in a function component and we'd want to persist this value of opened between function call, a react hook in a function component will be ideal in your case.
//let opened = false;
// *suggestion as per react documentation: useState hook lets us keep local state in a function component
const [opened, setOpened] = useState(false);
// ***you don't really need this part, see my approach in second div of return
// const toggle = () => {
// opened = !opened;
// };
return (
<div className={opened ? 'some-class opened' : 'some-class'}>
<div className="some-inner-class" onClick={() => setOpened(true)}>
<p>Click me</p>
</div>
</div>
);
};
export default Something;
You need to update state in React for a rerender to occur. You should be creating state in a constructor like:
constructor() {
super();
this.state = { toggled: false };
}
Then, in your toggle function you need to call
this.setState({toggled: !this.state.toggled});
Currently your component is a stateless functional component so you would either need to rewrite it as a class that extends React.component or you could use hooks, https://reactjs.org/docs/hooks-state.html. Since it looks like you're just starting to learn how to use React I would rewrite the component as a class first and then try to refactor it using hooks (the modern practice).

Jest expected mock not called (redux component)

In React, I am testing that a button click inside a child component causes a function to be called in the parent component (onDeleteClick), via event bubbling.
For this test, I am using mount, as shallow will not allow us to trigger a function in a child component.
onDeleteClick, the function I am trying to check whether it was called or not, is a class property which in this case, is an arrow function.
I am mocking the onDeleteClick function, and passing it into my component via a Redux Provider when starting the test.
The problem I am having is that at the end of the test, when I perform a check to see if the mocked function was called, it returns 0.
expect(onDeleteClick.mock.calls.length).toBe(1);
If I put a console.log within onDeleteClick(), it's outputted during the test, so I know that the function is in fact being called.
I have researched this quite a bit and so far haven't gotten anything to work.
Some suggestions were to spy on my mocked function, and then call forceUpdate on the wrapper, but this didn't yield any positive results.
For this, I am using Jest with Enzyme.
Reference Code:
Parent.js
import { deleteAccount } from '../../actions/profileActions';
import ChildComponent from '../common/ChildComponent';
class ParentComponent extends Component {
onDeleteClick = () => {
console.log('onDeleteClick was executed during this test!')
this.props.deleteAccount();
}
render() {
let dashboardContent;
dashboardContent = (
<div>
<ChildComponent onDelete={this.onDeleteClick} />
</div>
);
return (
<div>
{dashboardContent}
</div>
);
}
}
// propTypes and mapStateToProps removed from this post
export default connect(
mapStateToProps,
{ deleteAccount }
)(ParentComponent);
__tests__/ParentComponent.js
import React from 'react';
import { mount } from 'enzyme';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import ParentComponent from '../ParentComponent';
import thunk from "redux-thunk";
const mockStore = configureStore([thunk]);
const deleteAccount = jest.fn();
const props = {
deleteAccount
}
const randomTestState = {
// some initial state, not important
};
const randomTestStore = mockStore(randomTestState);
describe('<ParentComponent />', () => {
it(`mounts the ParentComponent component and, when ChildComponent sends onDelete, then deleteAccount function is called once`, () => {
const wrapper = mount(
<Provider store={randomTestStore} props={props}>
<Router >
<ParentComponent />
</Router>
</Provider>
);
// Here, I grab an element in ChildComponent and simulate a click using Enzyme, then the event bubbles up, and deleteAccount() is called in the parent component.
// the console.log we expect to see from onDeleteClick is logged to console.
// the call does not seem to have registered though and the expect returns falsy
expect(deleteAccount.mock.calls.length).toBe(1);
})
});
Could the problem be that I am wrapping the component in a Provider?
I have a hunch, but I couldn't find any concrete examples of tests which use a Provider to wrap their component when running integration testing
The solution was that I needed to change my main ParentComponent file from
class ParentComponent extends Component {
to this:
extend class ParentComponent extends Component {
and then in my test file, import the component like so:
import { ParentComponent } from '../ParentComponent'; // non-default export should be wrapped in braces
and then update my test so that I assign the wrapper variable like so:
const wrapper = mount(<ParentComponent {...props} />);
This then allowed the test to pass
expect(deleteAccount.mock.calls.length).toBe(1);
It was recommended here in the Redux docs

FindDOMNode flux/alt store

I'm trying to access a dom node from a store (using alt) in order to animate using velocity.js, however am only getting 'cannot read property of undefined'. Is it possible to use findDOMNode from an alt/flux store?
import React from 'react'
import alt from '../_alt';
import Actions from '../actions/actions';
import Velocity from 'velocity-animate/velocity';
import Body from '../modules/level_1/body/body1'
class Store {
constructor(){
this.bindListeners({
menuToggle: Actions.MENU_TOGGLE
});
this.menuStatus = false
}
menuToggle(){
if (!this.menuStatus){
this.menuStatus = true;
Velocity(React.findDOMNode(Body.refs.wrap),({ width: '50px' }), 50)
} else {
this.menuStatus = false;
}
}
}
export default alt.createStore(Store, 'Store');
Component:
import React from 'react';
import connectToStores from 'alt/utils/connectToStores';
import Store from '../../../stores/store'
import Actions from '../../../actions/actions';
import Styles from './body1.css';
import Hero from '../../objects/hero/full_width'
let image = ['../../../../assets/full_width1.jpg', 'image']
#connectToStores
export default class Body extends React.Component {
static getStores(){
return [Store];
}
static getPropsFromStores(){
return Store.getState();
}
render(){
return (
<div ref='wrap'>
<Hero content={image} />
</div>
);
}
}
Body is a react class, which does not have refs.
What you need is a react element (an instance of a react class) which is the "this" inside of render, componentDidMount, etc.
You will have to provide the react element to the store in some way (probably by calling menuToggle with the actual react element).
Alternatively you could use componentDidMount to set the ref on the Body class so that toggle could consume it.
A pattern that I have used with some success is to create an initialize action that takes as one of its arguments a React component. Then in componentDidMount() you can call that action, passing this as an argument. This allows your store to have a handle on that React element, as well as all of its associated properties so you can do things like React.findDOMNode(component.refs['someref']).

Categories

Resources