I'm currently in the process of learning react and have come across a problem has had me stuck for most of the day. I have two simple components. Once called IncidentsBoard which holds other components called Incidents.
The idea is that (using dummy data) the IncidentBoard will show incidents of car crashes on it. My code:
IncidentBoard:
import React from 'react';
import Incident from './Incidents';
import testData from './testdata';
class IncidentBoard extends React.Component {
constructor(props) {
super(props);
this.state = {
data: testData.features,
filtered: []
}
}
componentWillMount() {
var filtered = this.state.data.filter( (incident, i) => {
return incident.properties.event_type === 'Crash';
})
console.log(filtered);
this.setState({filtered})
}
render() {
return <div>
{this.state.filtered.map((incident, i) => {
return <Incident id={i} description="swagg" />
})}
</div>
}
}
export default IncidentBoard;
Incident (which is currently mostly empty):
import React from 'react';
class Incident extends React.Component {
render() {
return <div><h1>test</h1></div>
}
}
export default Incident;
When running this, it causes an infinite loop where componentWillMount() is run without end. I have also noticed that if I replace the Incident component in the render function in IncidentBoard that the error no longer happens.
EDIT: More code
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import IncidentBoard from './Incidents';
ReactDOM.render(
<IncidentBoard />, document.getElementById('react-container')
)
testData is a just a big JSON object.
Related
in the first react file i called an api to get some data and save it in this.state.Data
import React, { Component } from "react";
import axios from "axios";
import Layout from "./Layout";
class Db extends Component {
constructor() {
super();
this.state = {
Data: [],
};
}
componentDidMount() {
axios.get(`https://breakingbadapi.com/api/characters`).then((res) => {
const data = res.data;
this.setState({ Data: data });
});
}
render() {
return <h1>DB working</h1>;
}
}
export default Db;
in the another react file i need to get this.props.Data from Db.js file but i dont know how to get it
import React, { Component } from "react";
import Db from "./Db";
class Filler extends Component {
constructor() {
super();
}
render() {
return <div></div>;
}
}
export default Filler;
for small projects you can use React ContextApi to save states in global level and use it inside components you want.
for big projects you can use state management libraries like Redux. it's too much for small projects.
This is my class:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from 'react-intl';
class MyClass extends Component {
constructor(props) {
super(props);
}
get pageTitle() {
const { intl } = this.props;
return intl.formatMessage({id: 'messages_my_class_page_title'});
}
render() {
return (
<div>
Dummy content
</div>
);
}
}
MyClass.propTypes = {
intl: intlShape.isRequired
}
export default injectIntl(MyClass);
My page title appears when I put in a random text and don't use react-intl injectIntl function.
I have 'react-intl' working fine for all other cases. Even for static properties using 'hoist-non-react-statics' library.
I am stumbled upon this one.
Edit 1:
I can fix it using
<FormattedMessage id="messages_my_class_page_title"/>
But I want to know how to use injectIntl way.
I need advice on how to pass a Reactjs prop from a component to my app when it's loaded. I'm able to pass the value when my props are in app.js but how do I handle the prop when loading from a separate component?
Here's what's working so far in app.js:
import React, { PropTypes, Component } from 'react';
import { Grid, Nav, Navbar, NavItem, Jumbotron } from 'react-bootstrap';
import { Link } from 'react-router';
import { LinkContainer, IndexLinkContainer } from 'react-router-bootstrap';
function HeaderTitle(props) {
return <h1>{props.name}</h1>;
}
const headerTitle = <HeaderTitle name="About Page" />;
class App extends React.Component {
constructor(props) {
super(props);
}
render() { ...
<p>{headerTitle.props.name}</p>
Parent to Child
If you want to pass all the props through:
render() {
return (
<div>
<HeaderTitle {...this.props} />
</div>
);
}
Or if just some:
render() {
return (
<div>
<HeaderTitle name={this.props.name} />
</div>
);
}
Child to Parent
If you mean the other way round, you need to use a callback
// app
render() {
return (
<div>
<HeaderTitle onGetName={(name) => this.setState({childName: name})} />
<p>{this.state.childName}</p>
</div>
);
}
// headertitle
componentDidMount() {
// maybe some async call or something
axios
.get('/api/say-my-name')
.then(response => this.props.onGetName(response.data);
}
So I guess you need some thing like importing components from one file to another. So you have options to import and export components from another file since React components are basically Objects. In index.js if you have something like
const headerTitle = <HeaderTitle name="About Page" />;
export default headerTitle;
and in app.js
import React, { PropTypes, Component } from 'react';
import { Grid, Nav, Navbar, NavItem, Jumbotron } from 'react-bootstrap';
import { Link } from 'react-router';
import { LinkContainer, IndexLinkContainer } from 'react-router-bootstrap';
import HeaderTitle from '/// put the file relative location to app.js"
function HeaderTitle(props) {
return <h1>{props.name}</h1>;
}
class App extends React.Component {
constructor(props) {
super(props);
}
render() { ...
<p>{headerTitle.props.name}</p>
}
I have a React component that I am trying to test using Enzyme/Jest. I am trying to figure out what the most appropriate test would be to ensure the component has rendered.
My component has a prop shouldRender that, if false, will cause the component to not render. My component looks like this:
import React from 'react';
const propTypes = {
shouldRender: React.PropTypes.bool,
};
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
foo: 'bar',
};
}
render() {
if (!this.props.shouldRender) {
return null;
}
return (
<div>
<span>My component</span>
</div>
);
}
}
MyComponent.propTypes = propTypes;
export default MyComponent;
I have a test that looks like this:
import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from '../MyComponent';
describe('MyComponent', () => {
it('Should render if we want it to', () => {
const component = shallow(<MyComponent shouldRender />);
expect(component).toBeDefined(); // Passes
});
it('Should not render if we do not want it to', () => {
const component = shallow(<MyComponent />);
expect(component).not.toBeDefined(); // Does not pass, as component isn't undefined.
});
});
I'd like the second test to fail, as the component isn't rendering. Is there a better way to go about testing whether or not a component has rendered?
Happy to provide any more information if it is needed.
Thanks!
So I've had a chat to some people and decided that maybe I am going about this the wrong way.
It's probably a better idea to determine whether or not this gets rendered by the parent component, otherwise any time I want to use MyComponent, I am going to have to pass this shouldRender prop into it.
MyComponent now looks like this:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
foo: 'bar',
};
}
render() {
return (
<div>
<span>My component</span>
</div>
);
}
}
MyComponent.propTypes = propTypes;
export default MyComponent;
and MyParentComponent that uses MyComponent looks like this:
import React from 'react';
const propTypes = {
myComponent: React.PropTypes.bool,
};
class MyParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
boz: 'baz',
};
}
render() {
return (
<div>
{ this.props.myComponent &&
<MyComponent />
}
</div>
);
}
}
export default MyComponent;
Not only does allow MyComponent to be more reusable, it removes the need for the test I wanted to write altogether. Thank you to everyone that looked at this.
I think Jest's snapshot testing is what you need. With snapshot testing when a test fails you can check to see if it's intended or unintended change. Check out their example here
I am starter in react & redux. I want to make todolist app. but when I insert a list into a store the displayList() function is not re-render. How can I fix this.
This is my reducer code.
export default function(state = ['start1','start2'], actions) {
switch(actions.type) {
case 'APPEND_ITEM':
state.push(actions.payload.item)
return state
break
}
return state
}
And this is my todolist.js code.
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import ReactDOM from 'react-dom'
import React from 'react'
class TodoList extends React.Component {
displayList(){
return this.props.dispatchs.map((item) => {
return(
<li key={ Math.random() }>{item}</li>
)
})
}
render(){
return(
<div>
{ this.displayList() }
</div>
)
}
}
var mapStateToProps = (state) => {
return {
dispatchs: state.dispatch
}
}
export default connect(mapStateToProps)(TodoList)
pin 2,3 does not re-render on the screen
Thank you for help.
Instead of using push in the reducer, return [ ... state, action.payload.item ]
case 'APPEND_ITEM':
return [ ...state, action.payload.item ]
This is because React will see the new state (object reference) equal to the old one, and decide not to re-render since it seems like nothing have changed