How I can remove not related to render data? - reactjs

How can I remove arrays from the render that, in fact, should not be there (commitsContentValues, membersContentValues, commitsValue, memberValue) and move it to separate methods. How can I make my code cleaner? And in which chapter of the reсt documentation is it described?
export default class Content extends Component {
constructor(props) {
super(props);
this.state = {
iteams: {},
};
}
async componentDidMount() {
membersData = 123
commitsData =zxc
this.setState({
iteams: { membersData, commitsData },
});
} catch {
console.log(err);
}
render() {
const { iteams } = this.state;
const commitsContentValues = { //this
firstRowText: "Date",
secondRowText: "Author",
thirdRowtext: "Commit Message",
firstRowKey: "committed_date",
secondRowKey: "author_name",
thirdRowkey: "title",
};
const membersContentValues = { //this
firstRowText: "Username",
secondRowText: "Name",
thirdRowtext: "GitLab Id",
firstRowKey: "username",
secondRowKey: "name",
thirdRowkey: "id",
};
const commitsValue = { //this
dataKey: "commitsData",
arrKey: "commits",
};
const memberValue = { //this
dataKey: "membersData",
arrKey: "members",
};
return (
<div>
{this.props.idx === 0 && (
<BasicTable
commits={iteams.commitsData}
commitsData={commitsContentValues}
keys={commitsValue}
></BasicTable>
...

The easiest solution is to just have the values you want returned from a function as you said:
export default class Content extends Component {
constructor(props) {
super(props);
this.state = {
iteams: {},
};
}
function getCommitsContentValues() {
return {
firstRowText: "Date",
secondRowText: "Author",
thirdRowtext: "Commit Message",
firstRowKey: "committed_date",
secondRowKey: "author_name",
thirdRowkey: "title",
};
}
render() {
return (
<div>
<BasicTable
commitsData={this.getCommitsContentValues()}
></BasicTable>
</div>
)
}
}
Is this what you are trying to do?

Related

how to create refs for content that gets created later

I have a component that fetches data from an api upon user input. This data then gets rendered onto the screen as <li/> tags. I want those <li/> tags to have a ref.
I tried creating an object of refs that I create after the data is fetched:
this.singleRefs = data.reduce((acc, value) => {
acc[value.id] = React.createRef();
return acc;
}, {});
and then later assign these refs to the <li/> tag: <li ref={this.singleRefs[element.id]}>
but when I print them out I always have {current:null} Here is a demo
what am I doing wrong?
With dynamic ref data, I'd propose that you should use callback refs.
import React from "react";
import "./styles.css";
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
this.singleRefs = {};
}
componentDidMount() {
const data = [
{ value: "val1", id: 1 },
{ value: "val2", id: 2 },
{ value: "val3", id: 3 }
];
this.myFunc(data);
//you don't need this anymore
// this.singleRefs = data.reduce((acc, value) => {
// acc[value.id] = React.createRef();
// return acc;
// }, {});
}
myFunc = async (data) => {
await sleep(3000);
this.setState({ data });
};
renderContent() {
return this.state.data.map(
function (element, index) {
return (
<li key={index} ref={(node) => (this.singleRefs[element.id] = node)}>
{element.value}
</li>
);
}.bind(this)
);
}
render() {
console.log(this.singleRefs);
return <ul>{this.renderContent()}</ul>;
}
}
Sandbox

How to reload "url" every second using React

I want to reload URL every 5 seconds. Below is my code. What do I do wrong? Please let me know is there anything important point which I missed.
class RandomImg extends Component {
constructor(props) {
super(props);
this.state = { image: "https://picsum.photos/100" };
}
componentDidMount() {
this.imgID = setInterval(() => {
this.tickImg();
}, 1000);
}
componentWillUnmount() {
clearInterval(this.imgID);
}
tickImg() {
this.setState({ image: "https://picsum.photos/100" });
}
render() {
return (
<div>
<h4>This is Random IMG:</h4>
<img src={this.state.image}></img>
</div>
);
}
}
Your image URL is not changing and thus the component is not being updated.
Try this
class RandomImg extends Component {
constructor(props) {
super(props);
this.state = { image: "https://picsum.photos/100" };
}
componentDidMount() {
this.imgID = setInterval(() => {
this.tickImg();
}, 1000);
}
componentWillUnmount() {
clearInterval(this.imgID);
}
tickImg() {
this.setState({ image: "https://picsum.photos/100?" + Math.random() });
}
render() {
return (
<div>
<h4>This is Random IMG:</h4>
<img src={this.state.image}></img>
</div>
);
}
}
You URL is not changing on the tick so the state remains the same. Try adding some random string into the URL
for e.g.
tickImg() {
this.setState({random: this.state.random++ } , () => {
this.setState({ image: "https://picsum.photos/100?r=" + this.state.random });
})
}
class RandomImg extends Component {
constructor(props) {
super(props);
this.state = { image: "https://picsum.photos/100" };
}
componentDidMount() {
this.imgID = setInterval(() => {
this.tickImg();
}, 5000);
}
componentWillUnmount() {
clearInterval(this.imgID);
}
tickImg() {
this.setState({
image: `https://picsum.photos/${Math.floor(Math.random()*100)}`
});
}
render() {
return (
<div>
<h4>This is Random IMG:</h4>
<img src={this.state.image}></img>
</div>
);
}
}

React component doesn't change parent's state

In component BlocklyDrawer i'm trying to change the code state of the parent component. I do it in the onChange() event, calling the method of the parent component handleCodex:
constructor(props) {
super(props);
this.state = {
code : "xxx",
};
this.handleCodex =
this.handleCodex.bind(this);
}
handleCodex(codex){
this.setState = ({
code: codex,
});
}
<BlocklyDrawer
tools={[INICIAR, MOVER, ATACAR]}
language = {Blockly.Javascript}
onChange={(code, workspace) => {
this.handleCodex(code);
}}
appearance={
{
categories: {
Agente: {
colour: '160'
},
},
}
}
>
Although the method handleCodex is executed, the code state does not change.
constructor(props) {
super(props);
this.state = {
code : "xxx",
};
this.handleCodex =
this.handleCodex.bind(this);
}
handleCodex(codex){
this.setState({
code: codex,
}); // this.setState is like a function call. Not a assignment statement.
}
<BlocklyDrawer
tools={[INICIAR, MOVER, ATACAR]}
language = {Blockly.Javascript}
onChange={(code, workspace) => {
this.handleCodex(code);
}}
appearance={
{
categories: {
Agente: {
colour: '160'
},
},
}
}
>

Assigning state to props from redux does not work

import React, { Component } from 'react';
import DisplayTable from './Table.js';
class App extends Component {
constructor(props) {
super(props);
this.state = {
menuItems: this.props.menu_items,
searchString: '',
displayItems: this.props.menu_items
}
this.search = this.search.bind(this);
this.handleChange = this.handleChange.bind(this);
}
componentWillMount() {
this.props.get_menu_items_api(false);
}
componentWillReceiveProps(nextProps) {
this.setState({ menuItems: nextProps.menu_items })
}
handleChange(e, isEnter) {
const searchData = () => {
let tempMenuProductDetails = this.props.menu_items;
const filterArray = tempMenuProductDetails.reduce((result, category) => {
if (category.categoryName.toLowerCase()
.indexOf(this.state.searchString.toLowerCase()) > -1) {
result.push(category);
}
if (category.productList && category.productList.length > 0) {
category.productList = category.productList.reduce((productListResult,
productList) => {
if (!!productList.productName &&
productList.productName.toLowerCase()
.indexOf(this.state.searchString.toLowerCase()) > -1)
{
productListResult.push(productList);
}
return productListResult;
}, []);
}
return result;
}, []);
this.setState({
displayItems: filterArray
}, function () {
console.log(this.state.displayItems);
})
console.log(filterArray);
}
if (!isEnter) {
this.setState({
searchString: e.target.value
});
} else {
searchData();
}
}
search(e) {
if (e.keyCode == 13) {
this.handleChange(e, true);
}
this.handleChange(e, false);
}
render() {
console.log(this.state.displayItems);
console.log(this.props.menu_items);
console.log(this.state.menuItems);
return (
<DisplayTable dataProp={this.state.displayItems} editFuncProp=
{this.props.edit_menu_items_api} /> )
}
}
export default App;
I have this search function in this file that does not update the value of props coming from the container of redux. Now when I pass {this.state.displayItems} in menu ,it does not display the data.
But when I pass {this.props.menu_items} it displays the data and I am not able to modify this.props.menu_items on the basis of search.
I have tried this code . what should i do?
The problem seems to be that, initially this.props.menu_items is an empty array and only after some API call the value is updated and you get the returned array on the second render, thus if you use it like
<DisplayTable dataProp={this.props.menu_items} editFuncProp=
{this.props.edit_menu_items_api} />
it works. Now that you use
<DisplayTable dataProp={this.state.displayItems} editFuncProp=
{this.props.edit_menu_items_api} />
and displayItems is only initialized in the constructor which is only executed once at the time, component is mounted and hence nothing is getting displayed.
The solution seems to be that you update the displayItems state in componentWillReceiveProps and call the search function again with the current search string so that you search results are getting updated.
Code:
import React, { Component } from 'react';
import DisplayTable from './Table.js';
class App extends Component {
constructor(props) {
super(props);
this.state = {
menuItems: this.props.menu_items,
searchString: '',
displayItems: this.props.menu_items
}
this.search = this.search.bind(this);
this.handleChange = this.handleChange.bind(this);
}
componentWillMount() {
this.props.get_menu_items_api(false);
}
componentWillReceiveProps(nextProps) {
this.setState({ menuItems: nextProps.menu_items, displayItems: nextProps.menu_items })
this.handleChange(null, true);
}
handleChange(e, isEnter) {
const searchData = () => {
let tempMenuProductDetails = this.props.menu_items;
const filterArray = tempMenuProductDetails.reduce((result, category) => {
if (category.categoryName.toLowerCase()
.indexOf(this.state.searchString.toLowerCase()) > -1) {
result.push(category);
}
if (category.productList && category.productList.length > 0) {
category.productList = category.productList.reduce((productListResult,
productList) => {
if (!!productList.productName &&
productList.productName.toLowerCase()
.indexOf(this.state.searchString.toLowerCase()) > -1)
{
productListResult.push(productList);
}
return productListResult;
}, []);
}
return result;
}, []);
this.setState({
displayItems: filterArray
}, function () {
console.log(this.state.displayItems);
})
console.log(filterArray);
}
if (!isEnter) {
this.setState({
searchString: e.target.value
});
} else {
searchData();
}
}
search(e) {
if (e.keyCode == 13) {
this.handleChange(e, true);
}
this.handleChange(e, false);
}
render() {
console.log(this.state.displayItems);
console.log(this.props.menu_items);
console.log(this.state.menuItems);
return (
<DisplayTable dataProp={this.state.displayItems} editFuncProp=
{this.props.edit_menu_items_api} /> )
}
}
export default App;

why do I have "Warning: undefined(...): Cannot update during an existing state transition..." error?

so i have this in my code like this:
class TimersDashboard extends React.Component{
constructor() {
super(props);
this.state = {
timers: [
{id: uuid.v4(), text:'I am the first id' },
{ id:uuid.v4(), text:'I am the second text' }
]
};
}
clickEdit(id) {
this.openForm(id);
}
openForm(id) {
this.setState({
timers: this.state.timers.map((timer) => {
if(timer.id === id) {
return Object.assign({}, timer, { editFormOpen: true });
} else {
return timer;
}
})
});
}
handleCloseForm(id) {
this.closeForm(id);
}
closeForm(id) {
this.setState({
timers: this.state.timers.map((timer) => {
if(timer.id === id) {
return Object.assign({}, timer, { editFormOpen: false });
} else {
return timer;
}
})
});
}
}
render() {
return (
<Timer id={this.state.data[0].id} onEdit={this.clickEdit.bind(this)} onDelete = {this.handleCloseForm.bind(this)}/> // as if wroking on the first id
);
}
}
}
However, below, I passed the methods as props, the other component I tried to invoke these the same way, you can see their code is slightly similar in way.
class Timer extends React.Component {
constructor(props) {
super(props);
this.handleEditClick = this.handleEditClick.bind(this);
this.handleTrashClic = handleTrashClic.bind(this);
}
handleEditClick() {
this.props.onDelete(this.props.id);
}
handleTrashClick() {
this.props.onEdit(this.props.id);
}
render() {
return(
// ... onClick = {()=>this.handleEditClick(this.props.id)} ..
// ... onClick = {()=>this.handleTrashClick(this.props.id)} ..
);
}
}
}
I code them same way on other component, the delete method works on other component but I don't know why the Edit method does not and I can't make it work, I tried to pass the parentObj context, added .bind(this), But I cannot make it work. My error is "Warning: undefined(...): Cannot update during an existing state transition...". How do I make it work?
Created the same example in jsfiddle, its working. Try this:
Parent Component:
class TimersDashboard extends React.Component{
constructor(props) {
super(props);
this.state = {
timers: [
{id: 1, text:'I am the first text' },
{id: 2, text:'I am the second text' }
]
};
}
edit(id){
let timers = this.state.timers.map((timer) => {
if(timer.id === id) {
return Object.assign({}, timer, { editFormOpen: true });
} else {
return timer;
}
})
this.setState({timers});
}
remove(id){
let timers = this.state.timers.map((timer) => {
if(timer.id === id) {
return Object.assign({}, timer, { editFormOpen: false });
} else {
return timer;
}
})
this.setState({timers});
}
render() {
return (
<div>
<Timer id={1} edit={this.edit.bind(this)} remove={this.remove.bind(this)}/>
</div>
);
}
}
Child Component:
class Timer extends React.Component{
constructor(props) {
super(props);
this.state={};
}
edit(id){
this.props.edit(id);
}
remove(id){
this.props.remove(id);
}
render(){
return(
<div>
In Child Component:
<br/>
Id: {this.props.id}
<p onClick={this.edit.bind(this,this.props.id)}>Edit</p>
<p onClick={this.remove.bind(this,this.props.id)}>Remove</p>
*click on edit and remove to change the state
</div>
)
}
}
Check jsfiddle for working example: https://jsfiddle.net/wqkfqusk/

Resources