I have a React component called Widget and I want to display a list of widgets as a table.
Let's say the array of widgets looks like A, B, C, D, E, F, G and I will allow up to 3 TD per Table Row. So the result will look like the following.
A B C
D E F
G
Although the simple line skip can be done with css by using Ul but I have to us e a table for header labels.
I tried making the original array into list of arrays like [[A,B,C], [D,E,F], [G]]:
{
chunkedPartsArray.map((chunk, ind) => {
return (<tr>
{
chunk.map((obj, ind) => {
return {obj}
})
}
</tr>)
})
}
The above code gives me the following warning
Uncaught Error: Objects are not valid as a React child (found: object with
keys {obj}). If you meant to render a collection of children, use an array
instead or wrap the object using createFragment(object) from the React add-
ons. Check the render method of WidgetsTab.
How can I solve this?
You should wrap your widgets within a td element. I have shown a demonstration using characters.
class App extends React.Component {
render() {
var chunkedPartsArray = [['A','B','C'], ['D','E','F'], ['G']]
return (
<tbody>{chunkedPartsArray.map((chunk, ind) => {
console.log(chunk);
return (<tr>
{
chunk.map((obj, ind) => {
console.log(obj);
return <td>{obj}</td>
})
}
</tr>)
})
}</tbody>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react-dom.js"></script>
<div id="app"></div>
You can create a function out there and return html.
in react we need wrap the component into a div if it is more than one.
so you need a placeholder for child and return from function.
//in a file after imports
function getChunkedParts(chunk, ind){
function getChunks(obj, ind){return (<td>{obj}</td>)}
var chunks =chunk.map((obj, ind) =>getChunks(obj, ind));
return (<tr>{chunks} </tr>)
}}
//parent render
render{
var ChunkedParts = chunkedPartsArray.map((chunk, ind) =>getChunkedParts(chunk, ind);
return(<table>{ChunkedParts }</table>)
}
Related
The error I get:
Objects are not valid as a React child, If you meant to render a collection of children, use an array instead.
here res is a json which has nested arrays so i have used _.foreach for extracting it and state is successfully updating but problem lies in displaying it
class ViewExchange extends React.Component{
state={list:[],refresh:false}
componentWillMount(props){
if(_.isEmpty(Cookies.get())){
this.props.history.push("/signup")
}
else{
let platform = Cookies.get('platform')
axios.post('http://localhost:3001/user/viewexchange',{platform})
.then(res=>{
this.setState({list:res.data})
_.forEach(this.state.list,(value)=>{
_.forEach(value.url,(e)=>this.setState({list:[e]}))
})
})
}
}
renderList=()=>{
console.log("in method")
return this.state.list.map((item,key)=>{
return <div key={key}>{item}</div>
})
}
render(){
return (
<div>
{this.renderList()}
</div>
);
}
}
export default withRouter(ViewExchange);
This error mostly comes when you try to show some content in jsx which is not a valid object key ( instead is an object itself ). In your case it will be like:
return this.state.list.map((item,key)=>{ return <div key={key}>{item.index}</dv> }); // instead of item, you have to use item.index which is an existing key of object
Here item.index is the index which you want to show from the object and don't forget to provide the key, in absence of key it will show a warning also performance is compromised.
I have simple component that represents instances of other component as html table.
class Table extends Component {
render() {
const { data } = this.props;
const articles= data.map((el, i) =>
<tr><td><Post post={el}/></td></tr>);
return <table>
{articles}
</table>;
}
Now I have only one table cell per row. I want to place three cells per row, for example.
I tried something like this
const articles = data.map(function(el, i) {
i++;
if (i == 1)
return <tr><td><Post post={el}/></td>;
else if (i % 3 == 0)
return <td><Post post={el}/></td></tr>;
else if (i % 4 == 0)
return <tr><td><Post post={el}/></td>;
else
return <td><Post post={el}/></td>;
});
This is a bad way, anyway. But in JSX this is impossible, because I get error "unterminated JSX contents".
ReactTable is not suitable for me, because I have table of another components, not data grid.
You can use lodash chunk to create an array with arrays where each sub-array represent a row.
Example
class Table extends React.Component {
render() {
const { data } = this.props;
const rows = _.chunk(data, 3);
const articles = rows.map((row, i) => (
<tr key={i}>
{row.map((cell, i) => (
<td key={i}>{cell}</td>
))}
</tr>
));
return <table>{articles}</table>;
}
}
ReactDOM.render(
<Table data={[1, 2, 3, 4, 5, 6, 7]} />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
An array of data should be split into chunks with any suitable implementation like Lodash. Then arrays of arrays can be processed:
return <table>
{_.chunk(data, 3).map(row => (
<tr>{row.map(el => (
<td><Post post={el}/></td>
)}</tr>
)}
</table>;
You are going about this the wrong way. A much simpler solution would be to simply manipulate your data into the shape in which you want to work with, and then write your code for rendering it.
That is..convert your data into a 2 dimensional array with 3 columns and ceil(n/3) columns where is the number of elements in your array.
Then you can simply map over the first dimension to create your <tr><tr/> elements and for each row you can map over the 3 elements to create your <td></td> elements.
Note that I am not saying that you cannot do this without creating this intermediate data source, merely that it is always easier if your data structure resembles your component hierarchy.
Coming from Vue.js (two way data flow) I have question about react one way data flow - I have a Parent that have a handler for its child onClick:
<div className="recipe-container">
<button onClick={this.toggleRecipeList.bind(this)}>Show Recipes</button>
<RecipeList showRecipe={this.showRecipe} list={this.state.recipes} />
</div>
So, I pass showRecipe handler, which has only one parameter (and simply just logs it to the console).
My RecipeList looks like this (stateless func):
return (<ul className='recipe-list-bottom'>
{
props.list.map((rec, key) => {
return <li onClick={props.showRecipe(rec)} key={key}>{rec.title}</li>
})
}
</ul>)
I tried to launch showRecipe(rec) to have the current rec object as argument. Although I recive what I want, the handler is being fired from a button which is a sibling of RecipeList.
I manage to get it working by adding onClick={props.showRecipe.bind(null,rec)} to li element, but I find it really dirty way to do so.
Am I missing something? I thought showRecipe(rec) would be enough to get what I wanted. Why showRecipe(rec) is being fired with this set to button?
I think that your second snippet has a classic error:
return (<ul className='recipe-list-bottom'>
{
props.list.map((rec, key) => {
return <li onClick={props.showRecipe(rec)/*here*/} key={key}>{rec.title}</li>
})
}
</ul>)
You are assigning the result of calling showRecipe to the onClick parameter, not the function itself. The bind solutions works, but if you want to pass the parameter rec without using bind you need to wrap the call:
return (<ul className='recipe-list-bottom'>
{
props.list.map((rec, key) => {
return <li onClick={()=>props.showRecipe(rec)} key={key}>{rec.title}</li>
})
}
</ul>)
You can use es2015 stage-0 syntax in order to write it like this:
class Blah extends Component {
onClick = (recipe) => e => this.props.showRecipe(recipe);
render() {
return (
<ul className='recipe-list-bottom'>
{
props.list.map((rec, key) => {
return <li onClick={onClick(rec)} key={key}>{rec.title}</li>
})
}
</ul>
)
}
}
I'm trying to iterate through an array stored in the store.
I get this red box error: can't find variable: city.
Is this a correct way to loop through an array in reactJS?
class CitiesPage extends Component {
render() {
return (
<View>
<Text>Cities Info:</Text>
<div>
{this.props.citiesArr}.map(function(city) {
<li key={city}>{city}</li>
});
</div>
</View>
);
}
}
My array inside the store looks like this:
const STORE_STATES = {
citiesArr: [
{city:'Rome', population:'34454'},
{city:'Paris', population:'45678'},
{city:'London', population:'2334'},
{city:'Milan', population:'23456'},
{city:'Amsterdam', population:'1234'},
{city:'Dublin', population: '234'},
{city:'Valencia', population: '2345'},
{city:'Ankara', population: '3456'}
]
};
{
this.props.citiesArr.map(function(city) {
<li key={city}>{city}</li>
})
}
// or ES6 arrow function
{this.props.citiesArr.map((city) => <li key={city}>{city}</li>)}
Instead of
{this.props.citiesArr}.map(function(city) {
<li key={city}>{city}</li>
});
In JSX (that code that looks like HTML but actually isn't), JavaScript has to be between { } and you misplaced the second one. Babel most likely transpiles your JSX into a code that does something totally different and causes the error. Check the transpiled source code if you're not 100% sure.
<div>
{
this.props.citiesArr.map((city) =>
<li key={city}>{city}</li>
);
}
</div>
Javascript is written inside jsx using { [your javascript code] }.
I'm just getting started with React. I have a project that includes many tables, some pretty complex, but all generally output a table from a set of data. Some have parent-child relationships (with toggleable child rows), and each has a slightly different format for the row output (e.g. some have buttons that open modals). Normally, I would use jQuery DataTables for this, which is easy and flexible for something like this. I'm struggling to figure out how to do it sustainably (scaleably?) in React, though.
I've written a basic table component where it accepts a set of items via props and spits out a table and handles child rows via internal state. Today I'll convert that to use two components: the table and a separate one for the rows. I really don't want to have to write X or 2X different components though (where X is the number of tables in the project), but I'm not sure how to make it reusable. All of the tables should have some things in common like style, filter capability, paging, etc., which I would try to put at the Table component level and reuse.
The best solution so far that I've thought about doing is passing in a preRender function via props and using that to create the actual row JSX, and having the render function just assemble all of those snippets into one output (which is basically what I do already but with Array.map. I could then provide the preRender via a prop (if that works), like this:
var Table = React.createClass({
render: function() { // mixin?
var rows = [];
for (var i=0; i<this.props.items.length; i++) {
rows.push(this.props.preRender(this.props.items[i]));
}
return rows; // plus html boilerplate...
}
});
var Parent = React.createClass({
render: function() {
var foodItems = this.state.foodItems;
var drinkItems = this.state.drinkItems;
var foodRender = function(i) { return (<tr>{i} <a href?>Buy me</a></tr>); }
var drinkRender = function(i) { return (<tr>{i} <button>Drink me</button></tr>); }
return (
<Table items={foodItems} preRender={foodRender}/>
<Table items={drinkItems} preRender={drinkRender}/>
);
}
});
Another thing I thought of was somehow passing in a different Row component to the Table component, if that's possible. I guess the root problems are:
The table-level stuff is very similar or identical across tables but may have parts needing customization per-table.
The rows do things like open popovers, so they will have a state (or need to circle around w/props).
Is there a better way to do this sort of logic/dependency injection, or will I probably just need to make a ton of slightly-different controls.
I'd start with something like this (using ES6 syntax for brevity):
const FoodItem = React.createClass({
render() {
return (
<tr><td>{this.props.item} Buy me</td></tr>
);
}
});
const DrinkItem = React.createClass({
render() {
return (
<tr><td>{this.props.item} <button>Drink me</button></td></tr>
);
}
});
const Table = React.createClass({
render() {
const {items, itemComponent: ItemComponent} = this.props;
return (
<table>
{items.map(item => <ItemComponent item={item} />)}
</table>
);
}
});
const Parent = React.createClass({
render() {
return (
<div>
<Table items={this.state.foodItems} itemComponent={FoodItem}/>
<Table items={this.state.drinkItems} itemComponent={DrinkItem}/>
</div>
);
}
});
An alternative pattern would be this (which is best depends on your requirements):
const FoodItem = React.createClass({
render() {
return (
<tr><td>{this.props.item} Buy me</td></tr>
);
}
});
const DrinkItem = React.createClass({
render() {
return (
<tr><td>{this.props.item} <button>Drink me</button></td></tr>
);
}
});
const Table = React.createClass({
render() {
// I'm assuming you ultimately want your table to do something cleverer than just rendering a table element
return (
<table>{this.props.children}</table>
);
}
});
const Parent = React.createClass({
render() {
return (
<div>
<Table>{this.state.foodItems.map(item => <FoodItem item={item} />)}</Table>
<Table>{this.state.drinkItems.map(item => <DrinkItem item={item} />)}</Table>
</div>
);
}
});