the following code doesn't update my component.
the state is updated with another function. so I'd assume the component would update aswell.
Entire Class is here.
class QuestionList extends Component
{
constructor(props)
{
super(props);
this.state = {
questions : []
}
this.childHandler = this.childHandler.bind(this);
}
updateData()
{
const get = '/application/questions/'
api.get(get)
.then(response => {
console.log(response);
this.setState({questions : response.data});
})
.catch(err => console.log(err));
}
componentDidMount(){
var tempArray = [];
const get = '/application/questions/'
api.get(get)
.then(response => {
console.log(response);
this.setState({questions : response.data});
})
.catch(err => console.log(err));
}
childHandler( update )
{
const {questions} = this.state;
let tempQs = questions;
const length = questions.length;
var temp = [];
var temp1 = [];
console.log ( tempQs );
for(var i = 0; i < length; i++)
{
if(questions[i].q_id == update[1])//find New
{
temp = [questions[i].q_id,questions[i].question];
for(var x = 0; x < length; x++)//find old
{
if(questions[x].q_id == update[0] && questions[x].q_id != questions[i].q_id )
{
temp1 = [questions[x].q_id,questions[x].question];
break;
}
}
break;
}
}
tempQs[temp[0]-1].question = temp1[1];
tempQs[temp1[0]-1].question = temp[1];
this.setState({questions : tempQs},console.log(questions));
}
render()
{
var { questions } = this.state;
console.log(questions);
var qs;
qs = questions.map(val => {
return(
<QuestionCards q_id={val.q_id} max={questions.length} action={this.childHandler}>{val.question}</QuestionCards>
)
});
return(
<Table hover>
<tbody>
<tr className="title">
<th>Id</th>
<th>Question</th>
<td colspan="3" ><Button color="primary">Add Question</Button></td>
</tr>
{qs}
</tbody>
</Table>
);
}
}
here is the cards component
class QuestionCards extends Component
{
constructor ( props )
{
super(props)
this.state = {
fireModal : false,
modal : false,
q_id : this.props.q_id,
question : this.props.children,
max : this.props.max
}
this.handleClick = this.handleClick.bind(this);
this.handleModal = this.handleModal.bind(this);
this.triggerModal = this.triggerModal.bind(this);
this.moveUp = this.moveUp.bind(this);
this.moveDown = this.moveDown.bind(this);
}
triggerModal ( trig )
{
const {q_id} = this.state;
if (trig)
return (
<QListModal q_id={q_id} trigger={trig} action={this.childHandler}/>
);
}
handleModal ( val )
{
const { fireModal } = this.state;
console.log('fireModel: ' + fireModal)
if( !fireModal )
{
this.setState({
mTarget : val,
fireModal : true ,
update : []
});
}
else
{
this.setState({fireModal:false})
}
}
moveUp ()
{
var tempArray = [];
const { q_id } = this.state;
const dir = 'up';
const get = '/application/move/' + q_id +'/'+ dir;
api.get(get).then(res => {
console.log(res);
this.setState({
update : [res.data.newId,res.data.oldId]
})
return this.props.action(this.state.update);
});
//return this.props.action(this.state.update);
}
moveDown ()
{
var tempArray = [];
const { q_id } = this.state;
const dir = 'down';
const get = '/application/move/' + q_id +'/'+ dir;
api.get(get).then(res => {
this.setState({
update : [res.data.newId,res.data.oldId]})
return this.props.action(this.state.update);
});
//return this.props.action();
}
render()
{
const {
fireModal,
q_id,
question,
max,
update
} = this.state
let ButtonUp;
let ButtonDown;
if( q_id <= 1)
{
ButtonUp = <td></td>
}
else
{
ButtonUp = <td><Button id={q_id} onClick={this.moveUp}>▲</Button></td>
}
if( q_id == max)
{
ButtonDown = <td></td>
}
else
{
ButtonDown = <td><Button id={q_id} onClick={this.moveDown}>▼</Button></td>
}
return(
<tr>
<th>{q_id}</th>
<td>{question}</td>
<td><Button onClick={this.handleModal}>Edit</Button></td>
{ButtonUp}
{ButtonDown}
{this.triggerModal(fireModal)}
</tr>
)
}
}
render()
{
var { questions } = this.state;
var qs = questions.map(val => {
return(
<QuestionCards q_id={val.q_id} max={questions.length} action={this.childHandler}>{val.question}</QuestionCards>
)
});
return(
<Table hover>
<tbody>
{qs}
</tbody>
</Table>
);
}
}
what the app is trying to do is every time the up or down arrow is pressed. it updates it on the page.
For some reason after updating the state it doesn't update the output itself.
though when i console.log the state it self it is updated.
this is my first independent project I'm still learning React/Javascript as a whole.
as you can see the state updates properly. but just doesn't re render anything.
the profiler tool in react-dev-tools outputs nothing rendered. could it be because of the parent component?
Solution
My problem was with the constructor for question cards.
super(props)
this.state = {
fireModal : false,
modal : false,
q_id : this.props.q_id,
question : this.props.children, // This line in particular
max : this.props.max
}
I wasn't updating the state with the new Info.
so i just assign the value of this.props.children to a constant in the render function
this is the updated render for QuestionCards
render()
{
const {
fireModal,
q_id,
max
} = this.state
const question = this.props.children;
let ButtonUp;
let ButtonDown;
if( q_id <= 1)
{
ButtonUp = <td></td>
}
else
{
ButtonUp = <td><Button id={q_id} onClick={this.moveUp}>▲</Button></td>
}
if( q_id == max)
{
ButtonDown = <td></td>
}
else
{
ButtonDown = <td><Button id={q_id} onClick={this.moveDown}>▼</Button></td>
}
return(
<tr>
<th>{q_id}</th>
<td>{question}</td>
<td><Button onClick={this.handleModal}>Edit</Button></td>
{ButtonUp}
{ButtonDown}
{this.triggerModal(fireModal)}
</tr>
)
}
also removed the console logs to declutter the post!
Thank you all for helping me trouble shoot!
Issue
Looks like a state mutation in cardHandler
childHandler( update ) {
const {questions} = this.state;
let tempQs = questions; // <-- saved current state ref to tempQs
...
tempQs[temp[0]-1].question = temp1[1]; // <-- mutated state ref
tempQs[temp1[0]-1].question = temp[1]; // <-- mutated state ref
this.setState({questions : tempQs},console.log(questions)); // <-- saved state ref
}
Solution
Shallow copy questions into new array reference to update. This should allow react's state/props reference test to detect that state is a new object and rerender.
const {questions} = this.state;
let tempQs = [...questions]; // <-- spread existing array into new array
Related
When I change a value in the table, it disappears when I update the state with the new value. I have checked state and it is updated correctly but the table is now blank. I am using a bootstrap table.
Everything in state is now updated but the grid is empty, can I use useEffect to do rebind the table?
const GridEdit = () => {
const store = useContext(StoreContext);
const handleBlur = (e, arrayRow, editableFields) => {
const newVals = store.gridItems[0][0];
newVals["Status"] = e.target.innerHTML;
store.gridItems[1](newVals);
console.log("hello ", store.gridItems[0]);
};
const dataTable = store.gridItems[0];
function tableHeaders(data) {
let tableHeaders = [];
if (data.length > 0) {
let headers = Object.keys(data[0]);
headers.map((header) =>
tableHeaders.push(<th key={header}>{header}</th>)
);
}
if (tableHeaders.length === 0) {
return null;
} else return tableHeaders;
}
function tableRows(dataTable) {
let tableLength = dataTable.length;
let table = [];
for (let i = 0; i < tableLength; i++) {
let children = [];
let row = Object.values(dataTable[i]);
const readOnlyFields = row.slice(0, 4);
const editableFields = row.slice(4, 7);
readOnlyFields.map((data) => children.push(<td id={row[0]}>{data}</td>));
editableFields.map((data) =>
children.push(
<td ContentEditable="true" id={row[0]}>
{data}
</td>
)
);
table.push(
<tr key={row} onBlur={(e) => handleBlur(e, i, editableFields)}>
{children}
</tr>
);
}
if (table.length === 0) {
return null;
} else {
return table;
}
}
return (
<tbody className="tableHeaders">
<tr>{tableHeaders(dataTable)}</tr>
{tableRows(dataTable)}
</tbody>
);
};
export default GridEdit;
I am trying to delete multiple items on click of checkbox using firestore. But, onSnapshot method of firestore is causing issue with the state.
After running the code I can click on checkbox and delete the items, the items get deleted too but I get an error page, "TyperError: this.setState is not a function" in onCollectionUpdate method.
After refreshing the page I can see the items deleted.
Here's my code:
class App extends React.Component {
constructor(props) {
super(props);
this.ref = firebase.firestore().collection('laptops');
this.unsubscribe = null;
this.state = { laptops: [], checkedBoxes: [] };
this.toggleCheckbox = this.toggleCheckbox.bind(this);
this.deleteProducts = this.deleteProducts.bind(this);
}
toggleCheckbox = (e, laptop) => {
if (e.target.checked) {
let arr = this.state.checkedBoxes;
arr.push(laptop.key);
this.setState = { checkedBoxes: arr };
} else {
let items = this.state.checkedBoxes.splice(this.state.checkedBoxes.indexOf(laptop.key), 1);
this.setState = {
checkedBoxes: items
}
}
}
deleteProducts = () => {
const ids = this.state.checkedBoxes;
ids.forEach((id) => {
const delRef = firebase.firestore().collection('laptops').doc(id);
delRef.delete()
.then(() => { console.log("deleted a laptop") })
.catch(err => console.log("There is some error in updating!"));
})
}
onCollectionUpdate = (querySnapshot) => {
const laptops = [];
querySnapshot.forEach((doc) => {
const { name, price, specifications, image } = doc.data();
laptops.push({
key: doc.id,
name,
price,
specifications,
image
});
});
this.setState({ laptops });
console.log(laptops)
}
componentDidMount = () => {
this.unsubscribe = this.ref.onSnapshot(this.onCollectionUpdate);
}
getLaptops = () => {
const foundLaptops = this.state.laptops.map((laptop) => {
return (
<div key={laptop.key}>
<Container>
<Card>
<input type="checkbox" className="selectsingle" value="{laptop.key}" checked={this.state.checkedBoxes.find((p) => p.key === laptop.key)} onChange={(e) => this.toggleCheckbox(e, laptop)} />
...carddata
</Card>
</Container>
</div>
);
});
return foundLaptops;
}
render = () => {
return (
<div>
<button type="button" onClick={this.deleteProducts}>Delete Selected Product(s)</button>
<div className="row">
{this.getLaptops()}
</div>
</div>
);
}
}
export default App;
In the toggleCheckbox function you set the this.setState to a object.
You will need to replace that with this.setState({ checkedBoxes: items})
So you use the function instead of setting it to a object
You probably just forgot to bind the onCollectionUpdate so this referes not where you expectit to refer to.
Can you pls also change the this.setState bug you have there as #David mentioned also:
toggleCheckbox = (e, laptop) => {
if (e.target.checked) {
let arr = this.state.checkedBoxes;
arr.push(laptop.key);
this.setState({ checkedBoxes: arr });
} else {
let items = this.state.checkedBoxes.splice(this.state.checkedBoxes.indexOf(laptop.key), 1);
this.setState({
checkedBoxes: items
})
}
}
If you already did that pls update your question with the latest code.
I have added sorting facility in my table. While I sort or delete an element, 2 arrays are coming same, one of prevprops and another of current props. I reviewed my code and found error coming from following piece of code.
Here is my Pagination.js code
import React from "react"
const propTypes = {
// items: React.PropTypes.array.isRequired,
// onChangePage: React.PropTypes.func.isRequired,
// initialPage: React.PropTypes.number
}
const defaultProps = {
initialPage: 1
}
class Pagination extends React.Component {
constructor(props) {
super(props);
this.state = { pager: {} };
}
componentWillMount() {
//set page if items array isn't empty
if (this.props.items && this.props.items.length) {
this.setPage(this.props.initialPage);
}
}
// componentDidUpdate(prevProps,prevState) {
// if (this.props.items !== prevProps.items) {
// this.setPage(this.props.initialPage);
// }
// }
componentWillReceiveProps (newProps) {
if (this.props.items !== newProps.items) {
this.setPage(this.props.initialPage);
}
}
setPage(page) {
var items = this.props.items;
var pager = this.state.pager;
if (page < 1 || page > pager.totalPages) {
return;
}
// get new pager object for specified page
pager = this.getPager(items.length, page);
// get new page of items from items array
var pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);
// update state
this.setState({ pager: pager });
// call change page function in parent component
this.props.onChangePage(pageOfItems);
}
getPager(totalItems, currentPage, pageSize) {
// default to first page
currentPage = currentPage || 1;
// default page size is 10
pageSize = pageSize || 10;
// calculate total pages
var totalPages = Math.ceil(totalItems / pageSize);
var startPage, endPage;
if (totalPages <= 10) {
// less than 10 total pages so show all
startPage = 1;
endPage = totalPages;
} else {
// more than 10 total pages so calculate start and end pages
if (currentPage <= 6) {
startPage = 1;
endPage = 10;
} else if (currentPage + 4 >= totalPages) {
startPage = totalPages - 9;
endPage = totalPages;
} else {
startPage = currentPage - 5;
endPage = currentPage + 4;
}
}
// calculate start and end item indexes
var startIndex = (currentPage - 1) * pageSize;
var endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
// create an array of pages to ng-repeat in the pager control
var pages = [...Array((endPage + 1) - startPage).keys()].map(i => startPage + i);
// return object with all pager properties required by the view
return {
totalItems: totalItems,
currentPage: currentPage,
pageSize: pageSize,
totalPages: totalPages,
startPage: startPage,
endPage: endPage,
startIndex: startIndex,
endIndex: endIndex,
pages: pages
};
}
render() {
var pager = this.state.pager;
if (!pager.pages || pager.pages.length <= 1) {
// don't display pager if there is only 1 page
return null;
}
return (
<ul className="pagination">
<li className={pager.currentPage === 1 ? 'disabled' : ''}>
<a onClick={() => this.setPage(1)}>First</a></li>
<li className={pager.currentPage === 1 ? 'disabled' : ''}>
<a onClick={() => this.setPage(pager.currentPage - 1)}>Previous</a>
</li>
{pager.pages.map((page, index) =>
<li key={index} className={pager.currentPage === page ? 'active' : ''}>
<a onClick={() => this.setPage(page)}>{page}</a>
</li>
)}
<li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
<a onClick={() => this.setPage(pager.currentPage + 1)}>Next</a>
</li>
<li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
<a onClick={() => this.setPage(pager.totalPages)}>Last</a>
</li>
</ul>
);
}
}
Pagination.propTypes = propTypes;
Pagination.defaultProps = defaultProps;
export default Pagination
Here is my App.js code
import React from 'react';
import "./App.css"
import Table from "./components/table"
import SearchBar from "./components/search"
import "antd/dist/antd.css";
import data from "./data"
import Pagination from "./components/pagination"
export default class App extends React.Component {
constructor(props){
super(props);
// var exampleItems = [...Array(150).keys()].map(i => ({ id: (i+1), name: 'Item ' + (i+1) }))
this.state={
filterText:"",
// products:data,
// currentPage: 1,
// todosPerPage: 3,
exampleItems:data,
pageOfItems: [],
}
this.onChangePage = this.onChangePage.bind(this);
this.handleRowDel = this.handleRowDel.bind(this)
}
// componentWillMount(){
//this.setState({exampleItems: this.state.products})
// }
onChangePage(pageOfItems) {
// update state with new page of items
this.setState({ pageOfItems: pageOfItems });
}
handleUserInput = (filterText) => {
this.setState({filterText:filterText})
}
handleProductTable = (evt) => {
let item = {
id: evt.target.id,
name: evt.target.name,
value: evt.target.value
};
let products = this.state.exampleItems;
let newProducts = products.map(function(product) {
Object.keys(product).forEach(key => {
// eslint-disable-next-line
if (key == item.name && product.id == item.id) {
product[key] = item.value;
}
})
// for (var key in product) {
// // eslint-disable-next-line
// console.log(key);
// if (key == item.name && product.id == item.id) {
// product[key] = item.value;
// }
// }
return product;
});
this.setState({exampleItems:newProducts});
};
async handleRowDel (product){
const { exampleItems } = this.state;
let index = exampleItems.indexOf(product);
exampleItems.splice(index, 1);
await this.setState({exampleItems:exampleItems});
};
handleAddEvent = (one,two,three,four) =>{
let products= this.state.exampleItems;
let count = + new Date();
let item={
id: count,
name: one,
price: two,
qty: three,
category: four,
}
products.push(item);
this.setState({exampleItems:products});
}
orderChange = (e) =>{
var trimText = e.substr(4);
var arrangeMethod = e.substr(0,3);
if(trimText === "price" || trimText === "qty") {
this.arrangeNumber(trimText, arrangeMethod);
}
if(trimText === "category"){
this.arrangeText(trimText,arrangeMethod);
}
}
arrangeNumber = (key,arrangeMethod) =>{
let arraycopy = this.state.exampleItems;
if(arrangeMethod === "asc"){
arraycopy.sort(function(a,b){
if(Number(a[key]) < Number(b[key])){ return -1;}
if(Number(a[key]) > Number(b[key])){ return 1;}
return 0
})
}
if(arrangeMethod === "des"){
arraycopy.sort(function(a,b){
if(Number(a[key]) > Number(b[key])){ return -1;}
if(Number(a[key]) < Number(b[key])){ return 1;}
return 0
})
}
this.setState({exampleItems:arraycopy});
}
arrangeText = (key,arrangeMethod) =>{
let arraycopy = this.state.exampleItems;
if(arrangeMethod === "asc"){
arraycopy.sort(function(a,b){
if((a[key]) < (b[key])){ return -1;}
if((a[key]) > (b[key])){ return 1;}
return 0
})
}
if(arrangeMethod === "des"){
arraycopy.sort(function(a,b){
if((a[key]) > (b[key])){ return -1;}
if((a[key]) < (b[key])){ return 1;}
return 0
})
}
this.setState({exampleItems:arraycopy});
}
handleClick = (event) =>{
this.setState({
currentPage: Number(event.target.id)
});
}
render(){
// const { currentPage, todosPerPage,products } = this.state;
// // Logic for displaying current todos
// const indexOfLastTodo = currentPage * todosPerPage;
// const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
// console.log(products.slice(indexOfFirstTodo,indexOfLastTodo));
// const currentTodos = products.slice(indexOfFirstTodo, indexOfLastTodo);
// const renderTodos = currentTodos.map((todo, index) => {
// return <li key={index}>{todo}</li>;
// });
// const pageNumbers = [];
// for (let i = 1; i <= Math.ceil(products.length / todosPerPage); i++) {
// pageNumbers.push(i);
// }
// const renderPageNumbers = pageNumbers.map(number => {
// return (
// <li
// key={number}
// id={number}
// onClick={this.handleClick}
// >
// {number}
// </li>
// );
// });
return(
<div>
{/* <SearchBar
filterText={this.state.filterText}
onUserInput={this.handleUserInput}
/> */
}
<Table
onProductTableUpdate={this.handleProductTable}
onRowAdd={this.handleAddEvent}
products={this.state.pageOfItems}
// currentTodos
onDelEve={this.handleRowDel}
filterText={this.state.filterText}
orderChange={this.orderChange}
/><div className="pagination">
{/* <ul id="page">
{renderPageNumbers}
</ul> */}
</div>
<div className="container">
<div className="text-center">
{/* {this.state.pageOfItems.map(item =>
<div key={item.id}>{item.name}</div>
)} */ }
<Pagination items={this.state.exampleItems} onChangePage={this.onChangePage} />
</div>
</div>
</div>
);
}
}
Can you please tell me, where I should change my code ?
You have several instances where you are mutating the state. In react, your state needs to be immutable, otherwise it's not possible to compare before and after, because before and after are the same thing. For example, you have this code here:
handleAddEvent = (one,two,three,four) => {
let products = this.state.exampleItems;
let count = + new Date();
let item = {
id: count,
name: one,
price: two,
qty: three,
category: four,
}
products.push(item);
this.setState({ exampleItems:products });
}
You need to make a copy of the state before you start making modifications. For example, replace the first line of the function with:
let products = [...this.state.exampleItems];
Note: You have this issue in multiple places, not just handleAddEvent. I show that function just as an example. You'll probably need to fix all cases where you're mutating state in order to resolve your issue.
I was trying to write a HOC that adds a prop if it's a certain type. I am iterating through it depth first. But when I try to set prop it says it's not extensible, I am trying to add prop of value to HEEHAW:
function fieldLayoutHOC(WrappedComponent: ComponentType) {
return (
class FieldLayoutWrap extends WrappedComponent {
static displayName = wrapDisplayName(WrappedComponent, 'FieldLayoutWrap')
render() {
const view = super.render()
// depth first - stack - last in first out
// iterate depth first until a Field is found
const elements = [view]; // stack
console.log('view:', view);
while (elements.length) {
const element = elements.pop();
const primative = typeof element;
if (primative === 'object') {
if (element.type === Field) {
// fields.push(element);
element.props.value = 'HEEHAW'; /////// not extensible error here
console.log('added value HEEHAWW');
} else {
if (element.props) {
const children = element.props.children;
if (children) {
if (Array.isArray(children)) {
elements.push(...children);
} else {
elements.push(children);
}
}
}
}
}
}
return view;
}
}
)
}
Am I doing it wrong?
Well I came up with my own solution. I'm not mutating the props, which added the complication of holding on to a mutable version of the tree. This can definitely use some cleaning.
function addPropsIfHOCFactory(predicate) { //
return function addPropsIfHOC(WrappedComponent) { // factory
return (
class FieldLayoutWrap extends WrappedComponent {
render() {
const view = super.render();
if (!this.addProps) return view;
// depth first - stack - last in first out
// iterate depth first until a Field is found
const viewElementNew = { node: view, parentElement: null };
const tree = [viewElementNew]; // stack // parentElement is ref to parentElement in elements
const elementsByDepth = {}; // key is depth, value is array of element's at that depth
const elementsByParentId = {}; // key is elementId of parent
let elementId = 0;
// console.log('view:', view);
let depthMax = 0;
while (tree.length) {
const element = tree.pop();
element.props = element.node.props ? element.node.props : undefined;
element.childrenElements = undefined;
element.clone = undefined;
element.depth = getDepth(element);
element.id = elementId++;
element.needsClone = false; // if true then clone, its set to true if props are changed
if (element.depth > depthMax) depthMax = element.depth;
if (!elementsByDepth[element.depth]) {
elementsByDepth[element.depth] = [];
}
elementsByDepth[element.depth].push(element);
const node = element.node;
const primative = typeof node;
if (primative === 'object' && node) {
if (predicate(node)) {
const addProps = isFunction(this.addProps) ? this.addProps(node) : this.addProps;
element.props = Object.assign({}, node.props ? node.props : undefined, addProps);
markBranchNeedsClone(element);
console.log('added props to node:', element.node);
}
}
if (node.props && node.props.children) {
const children = node.props.children;
const pushChild = child => {
const parent = element;
const childElement = {
node: child,
parentElement: parent
}
tree.push(childElement);
if (!elementsByParentId[parent.id]) elementsByParentId[parent.id] = [];
elementsByParentId[parent.id].push(childElement);
return childElement;
}
if (Array.isArray(children)) {
element.childrenElements = children.map(pushChild);
} else {
const child = children;
element.childrenElements = pushChild(child);
}
}
}
// do React.cloneElement from deepest first IF needsClone === true
let depth = depthMax + 1;
while (depth--) {
// console.log('doing now elementsByDepth[depth] of depth:', depth);
for (const element of elementsByDepth[depth]) {
if (typeof element.node === 'object' && element.node) {
if (!element.needsClone) {
element.clone = element.node;
} else {
let childrenClones = elementsByParentId[element.id];
if (childrenClones) {
if (childrenClones.length === 1) {
childrenClones = childrenClones[0].clone;
} else {
childrenClones = childrenClones.map(element => element.clone);
}
}
console.log('CLONING');
element.clone = React.cloneElement(element.node, element.props, childrenClones);
}
} else {
// its a string, number etc
element.clone = element.node;
}
}
}
// console.log('viewElementNew:', viewElementNew);
// console.log('elementsByDepth:', elementsByDepth);
// console.log('elementsByParentId:', elementsByParentId);
return viewElementNew.clone;
}
}
)
}
}
function isFunction(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}
function getDepth(element) {
let depth = 0;
let elementCur = element;
while (elementCur.parentElement) {
elementCur = elementCur.parentElement;
depth++;
}
return depth;
}
function markBranchNeedsClone(element) {
let elementCur = element;
while (elementCur) {
elementCur.needsClone = true;
elementCur = elementCur.parentElement;
}
}
Usage:
import React from 'react'
import ReactDOM from 'react-dom'
import addPropsIfHOC from 'add-props-if'
// MY FORM COMPONENT
class BlahDumb extends React.Component {
addProps = {
placeholder: 'INJECTED PLACEHOLDER'
}
render() {
return (
<form>
<label htmlFor="url">URL</label>
<div>
<input id="url" type="text" />
yeppers
</div>
<div>
<input id="foo" type="text" />
</div>
</form>
)
}
}
const BlahPropsAdded = addPropsIfHOC(node => node.type === 'input')
const Blah = BlahPropsAdded(BlahDumb);
// MY APP COMPONENT
class App extends React.PureComponent {
render() {
return (
<div className="app">
<Blah />
</div>
)
}
}
// RENDER
ReactDOM.render(<App />, document.getElementById('app'))
Here it is working - https://codesandbox.io/s/6y1lrn7yww
Here is a demo which adds props to <Field> children: https://codesandbox.io/s/9zp9207nvy
I am new to react and having a weird bug in my application. On page load the app checks if user has some subscribed tests, the respective tests are shown or else a error than no test found. Page initially shows no error message and then loads up the test which is weird. Please help
#
export default class PlaytestsIndex extends React.Component {
constructor (props, context) {
super(props, context);
this._onPlaytestStoreChange = this._onPlaytestStoreChange.bind(this);
this.state = {
playtests: PlaytestStore.getActivePlaytests()
};
}
componentDidMount () {
PlaytestStore.addChangeListener(this._onPlaytestStoreChange);
}
componentWillUnmount () {
PlaytestStore.removeChangeListener(this._onPlaytestStoreChange);
}
_onPlaytestStoreChange () {
this.setState({
playtests: PlaytestStore.getActivePlaytests()
});
}
render () {
const playtests = this.state.playtests;
if (playtests.length === 0) {
return (
<table className="table table-fixed content-section">
<tbody>
<tr className="disabled">
<td className="no-results center">No playtests found</td>
</tr>
</tbody>
</table>
);
}
const today = Moment().minute(0).hour(0).second(0).millisecond(0);
// how the groups of playtests are sorted
const sortOrderLabels = [
'Currently Active',
'Upcoming'
];
const timelineDateRows = _.chain(playtests)
.groupBy((playtest) => {
const startsOn = Moment(playtest._startsOnDateTime).minute(0).hour(0).second(0).millisecond(0);
if (today.isAfter(startsOn) || today.isSame(startsOn, 'day')) {
return 0;
}
return 1;
})
.toPairs() // [[idx, playtests], ...]
.sortBy((paired) => paired[0]) // by idx
.map((paired) => {
const [idx, playtests] = paired;
return (<TimelineDateRow key={sortOrderLabels[idx]} label={sortOrderLabels[idx]} playtests={playtests}/>);
})
.value();
return (
<div>
{timelineDateRows}
</div>
);
}
}
#