Here I am trying to set innerHTML from my Test.js on render inside my componentDidMount. On the process I am getting errors of Unhandled Rejection (TypeError): Cannot set property 'innerHTML' of null .
I have gone through few questions where it defined to use refs() but unfotunately not able to use this in my case.
Any suggestion how can I use refs() here in my example?
demo Test.js
function updateList() {
const json = JSON.parse(localStorage["values"]);
if (json) {
picture = json.picture;
if (picture) {
userPicture = picture.name;
}
}
console.log(userPicture, "userPicture");
document.getElementById('picture').innerHTML = userPicture;
}
async function getAll () {
await updateList();
}
export default {
getAll
};
TestComponent.js
import React from 'react';
import Test from './Test';
class TestComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
Test.getAll();
}
render() {
return (
<div className="test-item" >
<div className="test-picture" id="picture"> </div>
</div>
);
}
};
export default (injectIntl(TestComponent));
I believe this is what you want.
Code sandbox url - https://codesandbox.io/s/fervent-surf-n72h6?file=/src/index.js
App.component
import React from "react";
import { render } from "react-dom";
import Test from "./Test";
class App extends React.Component {
constructor(props) {
super(props);
this.divRef= React.createRef();
}
componentDidMount() {
Test.getAll(this.divRef);
}
render() {
return (
<div className="test-item">
<div className="test-picture" ref={this.divRef} id="picture">
Hello from component
</div>
</div>
);
}
}
const container = document.createElement("div");
document.body.appendChild(container);
render(<App />, container);
Test.js
function updateList(ref) {
ref.current.innerHTML = "Hello from Test.js";
}
async function getAll(ref) {
await updateList(ref);
}
export default {
getAll
};
Related
2 components :- ClickCounter, mouseHoverCounter !
1 HOC component to do the counting work.
earlier I was counting the click and mouse hover by writing separate counter method in each component(cliccounter,mousehovecounter),
but
now, I'm trying to pass the component into hoc counter & get the new component with only one change , where I'm passing a props to originalComponent and returning it to see the behavior but its now working...
import React, { Component } from 'react'
import updatedComponent from './hocCounter'
class ClickCounter extends Component {
constructor(props) {
super(props)
this.state = {
counter:0
}
}
ClickCounterHandler = () =>{
this.setState((prevState)=>{
return {counter:prevState.counter+1}
})
}
render() {
const count=this.state.counter
return (
<div>
<button onClick={this.ClickCounterHandler}>{this.props.name} Clicked {count} Times</button>
</div>
)
}
}
export default updatedComponent(ClickCounter)
import React, { Component } from 'react'
import updatedComponent from './hocCounter'
class HoverMouseCounter extends Component {
constructor(props) {
super(props)
this.state = {
counter:0
}
}
MouseOverCounter(){
this.setState((prevState)=>{
return {counter:prevState.counter+1}
})
}
render() {
const count=this.state.counter
return (
<div>
<h1 onMouseOver={this.MouseOverCounter.bind(this)}>{this.props.name} Hovered For {count} Time(s)</h1>
</div>
)
}
}
export default updatedComponent(HoverMouseCounter)
import React from 'react'
const updatedComponent = originalComponent => {
class newComponent extends React.Component {
render(){
return <originalComponent name='Harsh'/>
}
}
return newComponent
}
export default updatedComponent
In App.js, I'm returning
<ClickCounter></ClickCounter>
<HoverMouseCounter></HoverMouseCounter>
this only !
Check the error in the console,
index.js:1 Warning: <originalComponent /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements. at originalComponent
This means You are using the small letter in originalComponent
React components are expected to start with a capital letter
Try this in you HOC component
import React from 'react'
const updatedComponent = OriginalComponent => {
class NewComponent extends React.Component {
render(){
return <OriginalComponent name='Harsh'/>
}
}
return NewComponent
}
export default updatedComponent
I'm trying to use a function, which is in a different component from App.js.
and I'm having the syntax error, I don't know what did I do wrong. I have a button in App.js and when I click on it, that function from another component that I've mentioned earlier should trigger.
app.js:
import React from 'react';
import {shaking} from './components/Tree/Tree.js';
class App extends React.Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
shaking();
console.log("done !");
}
render() {
return (
<div>
<Tree className='tree' />
<Apples />
<Basket />
<br/>
<button className="start-btn" onClick={this.handleClick}>Start !</button>
<br/>
</div>
);
}
};
export default App;
And this is my another component:
import React from 'react';
import TreeSvg from './Tree-svg/TreeSvg.js';
import './Tree.sass';
export function shaking(){
const tree = document.getElemenetsByClassName(".tree-img")[0];
tree.classList.add("apply-shake");
console.log('shaked!');
}
class Tree extends React.Component{
constructor() {
super();
this.shaking = this.shaking.bind(this);
}
shaking() {
this.setState({shaked:'1'});
const tree = document.getElemenetByClassName(".tree-img");
tree.classList.add("apply-shake");
console.log('shaked!');
}
render(){
return(
<div className="tree-img">
<TreeSvg />
</div>
);
}
};
export default Tree;
Make your Tree component like this
import React from 'react';
import TreeSvg from './Tree-svg/TreeSvg.js';
import './Tree.sass';
export function shaking(){
const tree = document.getElementsByClassName(".tree-img")[0];
tree.classList.add("apply-shake");
console.log('shaked!');
}
class Tree extends React.Component{
constructor() {
super();
this.state = {
shaked : ''
}
shaking() {
this.setState({shaked:'1'});
const tree = document.getElementByClassName(".tree-img");
tree.classList.add("apply-shake");
console.log('shaked!');
}
render(){
return(
<div className="tree-img">
<TreeSvg />
</div>
);
}
};
export default Tree;
You do have 2 syntax errors in your code. Both are located at the Tree component file.
At your exported function (Line 6):
const tree = document.getElemenetsByClassName(".tree-img")[0];
replace Elemenets with Elements.
At the class method shaking() (Line 21):
const tree = document.getElemenetByClassName(".tree-img"); replace Elemenet with Element
I am building a react app that deals with budgeting and I have written the code for a BillContainer component and an AddBill component.
This is my code:
BillContainer.js
import React from 'react';
import BillList from './BillList';
import AddBill from './AddBill';
class BillContainer extends React.Component {
constructor(props) {
super(props)
this.state = {
bills: [
]
}
this.addBill = this.addBill.bind(this)
}
addBill(bill) {
this.setState((state) => ({
bills: state.bills.concat([bill])
}));
}
render() {
return (
<div>
<AddBill addNew={this.addBill} />
<BillList bills={this.state.bills} />
</div>
)
}
}
export default BillContainer;
and AddBill.js
import React from 'react';
class AddBill extends React.Component {
constructor(props) {
super(props)
this.state = {
newBill: ''
};
this.updateNewBill = this.updateNewBill.bind(this)
this.handleAddNew = this.handleAddNew.bind(this)
}
updateNewBill(e) {
this.setState({
newBill: e.target.value
})
}
handleAddNew(bill) {
this.props.addNew(this.state.newBill)
this.setState({
newBill: ''
})
}
render() {
return (
<div>
<input
type='text'
value={this.state.newBill}
onChange={this.updateNewBill}
/>
<button onClick={this.handleAddNew}> Add Bill </button>
</div>
)
}
}
export default AddBill;
and this is my AddBill.test.js test:
import React from 'react';
import ReactDOM from 'react-dom';
import Enzyme from 'enzyme';
import { shallow, mount, render } from 'enzyme';
import EnzymeAdapter from 'enzyme-adapter-react-16';
import AddBill from '../components/AddBill';
let Sinon = require('sinon')
Enzyme.configure({adapter: new EnzymeAdapter() });
it('Adds a bill to the list', () => {
const clickSpy = Sinon.spy(AddBill.prototype, 'handleAddNew');
const wrapper = shallow(
<AddBill />
);
wrapper.find('button').simulate('click');
expect(clickSpy.calledOnce).toEqual(true)
})
Im trying to test that a new bill gets added when the Add Bill button is clicked. I've passed the addBill function as a prop but the test is throwing the error TypeError: this.props.AddNew is not a function.
How do I prevent the error message and and make this.props.addNew() not undefined?
You can use jest.spyOn like so:
it('Adds a bill to the list', () => {
const wrapper = shallow(
<AddBill addNew={() => {}} />
);
const clickSpy = jest.spyOn(wrapper.instance(), 'handleAddNew');
wrapper.find('button').simulate('click');
expect(clickSpy).toHaveBeenCalledTimes(1);
})
You're not passing an addNew property:
const wrapper = shallow(
<AddBill addNew={yourAddNewFunction} />
);
I'm having a problem with the function fetch. I'm trying to send just a number for example "1", and I have access to this data in all child components, but after calling fetch, I'm no longer able to access this data.
App.jsx:
import React, { Component } from 'react'
import './App.css';
import fetch from 'isomorphic-fetch'
import Header from './Header'
import Content from './Content'
import Footer from './Footer'
class App extends Component {
constructor(props) {
super(props)
this.state = {
stripdata: null
}
}
componentWillMount() {
fetch(`http://localhost:3000/data/info.json`)
.then(results => results.json())
.then(data => {
this.setState({
stripdata: data
})
// console.log(this.state.stripdata)
})
.catch(err => {
console.log("Didn't connect to API", err)
})
}
render() {
// console.log(this.state.stripdata)
return (
<div className="App">
<Header onQuery={1}/>
{
(this.state.data === null) ? <div className="loading">Loading data...</div> : <Content onResult={this.state.stripdata}/>
}
<Footer />
</div>
);
}
}
export default App;
Content.jsx:
import React, { Component } from 'react'
import Result from './Result'
class Content extends Component {
constructor(props) {
super(props);
this.state = {
stripdata: this.props.onResult
};
}
componentWillMount() {
}
render() {
console.log("im an Content: " + this.state.stripdata)
return (
<div className="Content">
<Result stripdata={ this.state.stripdata }/>
</div>
);
}
}
export default Content;
Result.jsx:
import React, { Component } from 'react'
import PersonCard from './PersonCard'
class Result extends Component {
constructor(props) {
super(props);
this.state = {
stripdata: this.props.stripdata
};
}
componentWillMount() {
}
render() {
console.log("im the Result: " + this.state.stripdata)
return (
<div className="result">
<PersonCard />
</div>
);
}
}
export default Result;
Please help. This is blocking my progress.
Fix the issue here:
<Header onQuery={1}/>
{
(this.state.stripdata === null) ? <div className="loading">Loading data...</div> : <Content onResult={this.state.stripdata}/>
}
You need to check properties in state with name stripdata.
And btw, fetch has to be performed in ComponentDidMount, see https://daveceddia.com/where-fetch-data-componentwillmount-vs-componentdidmount/
The problem is that, in your Results, you are only using the value from props once: in the constructor, where you set to state.
You should not set value in state from props. Instead, just use the props directly. Change Result to as following, then it will work proper:
import React, { Component } from 'react'
import PersonCard from './PersonCard'
class Result extends Component {
constructor(props) {
super(props);
// removed setting state from props.stripdata
}
render() {
console.log("im the Result: " + this.props.stripdata) // <-- using props!
return (
<div className="result">
<PersonCard />
</div>
);
}
}
export default Result;
In general it is considered bad practice/antipattern to set state from props.
I try to get used to reflux and forked a example repo. My full code is here [ https://github.com/svenhornberg/react-starterkit ]
I want to create a timer component which gets the current time from a timestore, but it is not working. The DevTools does not show any errors. This must be some newbie mistakes, but I do not find them.
Edit1: I added a line in home //edit1
Edit2: I think the mistake may be in componentDidMount in home.jsx
FIXED I need to trigger my time, see my answer.
Store
import Reflux from 'reflux';
import TimeActions from '../actions/timeActions';
var TimeStore = Reflux.createStore({
listenables: timeActions,
init() {
this.time = '';
},
onCurrenttime() {
this.time = '13:47';
}
});
export default TimeStore;
Actions
import Reflux from 'reflux';
var TimeActions = Reflux.createActions([
'currenttime'
]);
export default TimeActions;
Component
import React from 'react';
class Timer extends React.Component {
constructor(){
super();
}
render() {
var time = this.props.time;
return (
<div>
{ time }
</div>
);
}
}
Timer.propTypes = {
time : React.PropTypes.string
}
export default Timer;
I wanted to use the timer component in the home.jsx
import React from 'react';
import ItemList from '../components/itemList.jsx';
import ItemStore from '../stores/itemStore';
import ItemActions from '../actions/itemActions';
import Timer from '../components/timer.jsx';
import TimeStore from '../stores/timeStore';
import TimeActions from '../actions/timeActions';
class Home extends React.Component {
constructor(props){
super(props);
this.state = {
items : [],
loading: false,
time : '' //edit1
};
}
componentDidMount() {
this.unsubscribe = ItemStore.listen(this.onStatusChange.bind(this));
this.unsubscribe = TimeStore.listen(this.onStatusChange.bind(this));
ItemActions.loadItems();
TimeActions.currenttime();
}
componentWillUnmount() {
this.unsubscribe();
}
onStatusChange(state) {
this.setState(state);
}
render() {
return (
<div>
<h1>Home Area</h1>
<ItemList { ...this.state } />
<Timer { ...this.state } />
</div>
);
}
}
export default Home;
I fixed it thanks to: How to Make React.js component listen to a store in Reflux
I have to trigger my time:
var TimeStore = Reflux.createStore({
listenables: TimeActions,
init() {
this.time = '';
},
onCurrenttime() {
this.trigger({
time : '13:47'
});
}
});