Re-Render From Child Component After State Change - javascript

So what I want is, whenever I click on any list item the item should get struck. I've changed the state but I'm not sure about how to re-render this with new state. Can anyone please let me know how to do this?
Please don't mind my mistakes, I'm a newbie to this and also suggest me how to do this in better way if needed.
Child Components
class TodoList extends Component {
render() {
return (
<ul>
{this.props.items.map(thing => (
<List
key={thing.id}
item={thing}
items={this.props.items}
listid={thing.id}
/>
))}
</ul>
);
}
}
class List extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
render() {
return <li onClick={this.handleClick}>{this.props.item.item}</li>;
}
handleClick(event) {
const items = this.props.items;
items[this.props.listid] = {
item: "<strike>" + event.target.value + "</strike>",
id: this.props.listid
};
console.log(items);
this.setState({
items
});
}
}

You need to keep todos state in a parent component, and allow to state change from the inner components.
For example:
App.js (here we keep todos in state, and pass toggle function, and todo items as props to child components:
import React, { Component } from "react";
import TodoList from "./TodoList";
class App extends Component {
state = {
todos: [
{
id: 1,
text: "todo 1",
completed: false
},
{
id: 2,
text: "todo 2",
completed: true
},
{
id: 3,
text: "todo 3",
completed: true
}
]
};
toggle = id => {
const updatedTodos = this.state.todos.map(todo => {
if (todo.id === id) {
return {
...todo,
completed: !todo.completed
};
}
return todo;
});
this.setState({
...this.state,
todos: updatedTodos
});
};
render() {
return <TodoList items={this.state.todos} toggle={this.toggle} />;
}
}
export default App;
TodoList.js
import React, { Component } from "react";
import Todo from "./Todo";
class TodoList extends Component {
render() {
return (
<ul>
{this.props.items.map(todo => (
<Todo key={todo.id} item={todo} toggle={this.props.toggle} />
))}
</ul>
);
}
}
export default TodoList;
Todo.js (here we call toggle function when handleClick, and pass the id of the todo)
import React, { Component } from "react";
class Todo extends Component {
handleClick = id => {
this.props.toggle(id);
};
render() {
const { id, text, completed } = this.props.item;
return (
<li onClick={() => this.handleClick(id)}>
{completed ? <strike>{text}</strike> : text}
</li>
);
}
}
export default Todo;
here is codesandbox:
https://codesandbox.io/s/polished-cloud-hmdw0

Related

How can I make a list of integers click on element with corresponding id?

I have a list of ids (integer) and I have multiple components.
After a request to my API, the component receives a list of ids that should already be active.
I want to simulate a click on each element with the same id as the one in my array. I know I can use refs to do that, but I don't undertstand how to make it works with a list of elements.
Here's my code :
import React, { Component } from 'react'
import InterestBox from './InterestBox'
import Axios from 'axios'
export class InterestList extends Component {
constructor(props) {
super(props);
this.state = {pinterests: []}
}
componentDidMount() {
Axios.get('http://localhost:8000/api/interests')
.then((success) => {
this.setState({pinterests: success.data.data.interests});
})
}
componentDidUpdate(prevProps) {
console.log(JSON.stringify(prevProps));
console.log(JSON.stringify(this.props))
if(this.props.alreadyChecked != prevProps.alreadyChecked) {
this.props.alreadyChecked.forEach((item) => {
console.log(item)
})
}
}
render() {
return (
<React.Fragment>
{Object.keys(this.state.pinterests).map((interest) => {
var pinterest = this.state.pinterests[interest];
return <InterestBox id={pinterest.id} onClick={this.props.onClick} icon={pinterest.picture_src} title={pinterest.name} />
})}
</React.Fragment>
)
}
}
export default InterestList
import React, { Component } from 'react'
export class InterestBox extends Component {
constructor(props) {
super(props);
this.images = require('../../img/interests/*.svg');
this.state = {activated: false};
this.interest_box_content = React.createRef();
this.interest_text = React.createRef();
this.handleClick = this.handleClick.bind(this);
this.updateDimensions = this.updateDimensions.bind(this);
}
handleClick() {
this.props.handleClick(this.props.id, this.props.title);
this.setState(prevState => ({
activated: !prevState.activated
}))
}
updateDimensions() {
console.log((window.getComputedStyle(this.refs.interest_box_content).width))
this.refs.interest_text = (window.getComputedStyle(this.refs.interest_box_content).width)
}
render() {
return (
<div className="column is-one-fifth-desktop is-half-touch">
<div className="interest-box">
<div className="interest-box-adjuster">
<div ref={"interest_box_content"} className={"interest-box-content " + (this.state.activated == true ? 'interest-box-activated' : '')} onClick={this.handleClick}>
<img className="interest-icon" src={this.images[this.props.icon]} style={{'height': '50%'}}></img>
<i className="activated-icon fas fa-check"></i>
<span ref={"interest_text"} className="interest-text">{this.props.title}</span>
</div>
</div>
</div>
</div>
)
}
}
export default InterestBox
In the InterestList "componentDidUpdate" method, the value of the item is an integer.
I want to use this integer to "click" on the InterestBox with the corresponding "id".
How can I achieve this ?
You can store an array of elements in one ref, like this:
constructor(props) {
super(props);
this.state = {pinterests: []}
this.pinterestRefs = React.createRef()
}
...
render() {
return (
<React.Fragment>
{Object.keys(this.state.pinterests).map((interest) => {
var pinterest = this.state.pinterests[interest];
return <InterestBox id={pinterest.id} onClick={this.props.onClick} icon={pinterest.picture_src} title={pinterest.name} ref={pinterestRef => this.refs.pinterestRefs.push(pinterestRef)} />
})}
</React.Fragment>
)
}
and then call the click function on each in a componentDidMount function:
componentDidMount() {
if (this.refs.pinterestRefs.length) {
this.refs.pinterestRefs.forEach(pinterestEl => {
pinterestEl.click();
});
}
}
Since this.pinterestRefs is a ref and not an array, the push method is not available. Unfortunately, we do not have a definite length so we can't declare the refs preemptively. However, we can add it to this.refs object and the convert it to an array:
export class InterestList extends Component {
constructor(props) {
super(props);
this.state = {pinterests: []}
}
componentDidMount() {
Axios.get('http://localhost:8000/api/interests')
.then((success) => {
this.setState({pinterests: success.data.data.interests});
})
}
componentDidUpdate(prevProps) {
console.log(Object.values(this.refs)); // Array with all refs
console.log(JSON.stringify(prevProps));
console.log(JSON.stringify(this.props))
if(this.props.alreadyChecked != prevProps.alreadyChecked) {
this.props.alreadyChecked.forEach((item) => {
console.log(item)
})
}
}
render() {
return (
{/*I'm assuming each item has a unique id, if not, create one*/}
<React.Fragment>
{Object.keys(this.state.pinterests).map((interest) => {
var pinterest = this.state.pinterests[interest];
return <InterestBox id={pinterest.id} onClick={this.props.onClick} ref={pinterest.id} icon={pinterest.picture_src} title={pinterest.name} />
})}
</React.Fragment>
)
}
}
export default InterestList;

Get consolidated data from all the child components in the form of an object inside a parent component : React JS

I am implementing a setting page for an application. For each setting I have implemented a slider that has enabled(green) or disabled(red) state. But parent's settings is read only and is calculated based on the values of its children.
Parent's setting is derived as follows: If all children are red, parent stays red ; If all are green parent stays green; If at-least one of child is green then parent stays grey(Pending).
These settings are grouped something like this:
Parent Feature 1 : (read-only-toggle)
Setting 1 (Toggle)
Setting 2 (Toggle)
Parent Feature 2: (read-only-toggle)
Setting 1 (Toggle)
Setting 2 (Toggle)
And in the end there is also a button, that gives me a consolidated values of all parent and children. But so far I was able to do only with one parent and 2 children.
Can someone help with an approach of getting consolidated values of all the settings in one place(Like a super parent component where all these settings are configured).
For this , I am using react-multi-toggle for this toggle switch.
Help would be really appreciated.
Code Sandbox: https://codesandbox.io/s/react-multi-toggle-solution-perfect-v9bi5
App
import React from "react";
import ChildSwitch from "./ChildSwitch";
import ParentSwitch from "./ParentSwitch";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
parentVal: "disabled",
switch1Val: "enabled",
switch2Val: "disabled"
};
}
componentDidMount() {
this.setParentSwitchValue();
}
onGetChildSwitchValues = () => {
console.log(this.state);
};
setChildSwitchValue = (whichSwitch, selected) => {
this.setState(
prevState => ({ ...prevState, [whichSwitch]: selected }),
this.setParentSwitchValue
);
};
setParentSwitchValue = () => {
const { switch1Val, switch2Val } = this.state;
const switchStates = [switch1Val, switch2Val];
let parent = "pending";
if (switchStates.every(val => val === "enabled")) {
parent = "enabled";
}
if (switchStates.every(val => val === "disabled")) {
parent = "disabled";
}
this.setState(prevState => ({ ...prevState, parentVal: parent }));
};
render() {
const { parentVal, switch1Val, switch2Val } = this.state;
return (
<>
<div className="boxed">
Parent Setting 1 :{" "}
<ParentSwitch
parentSwitch={parentVal}
onSelect={this.setParentSwitchValue}
/>
Setting 1:
<ChildSwitch
switchName={"switch1Val"}
selected={switch1Val}
onSelect={this.setChildSwitchValue}
/>
Setting 2:
<ChildSwitch
switchName={"switch2Val"}
selected={switch2Val}
onSelect={this.setChildSwitchValue}
/>
</div>
<button onClick={this.onGetChildSwitchValues}>Get All Values</button>
</>
);
}
}
ChildSetting
import MultiToggle from "react-multi-toggle";
import React from "react";
export default class ChildSwitch extends React.Component {
constructor(props) {
super(props);
this.state = {
options: [
{
displayName: "Disabled",
value: "disabled"
},
{
displayName: "Enabled",
value: "enabled"
}
]
};
}
onSelectOption = selected => {
this.props.onSelect(this.props.switchName, selected);
};
render() {
const { options } = this.state;
const { selected } = this.props;
return (
<MultiToggle
options={options}
selectedOption={selected}
onSelectOption={this.onSelectOption}
/>
);
}
}
Parent Setting
import MultiToggle from "react-multi-toggle";
import React from "react";
import "react-multi-toggle/style.css";
export default class ParentSwitch extends React.Component {
constructor(props) {
super(props);
this.state = {
options: [
{
displayName: "Disabled",
value: "disabled"
},
{
displayName: "Pending",
value: "pending"
},
{
displayName: "Enabled",
value: "enabled"
}
]
};
}
render() {
const { options } = this.state;
return (
<MultiToggle
options={options}
selectedOption={this.props.parentSwitch}
onSelectOption={() => {}}
/>
);
}
}
I will suggest that you group your child and parent under one component. Let say we name it Settings. Then, we create another component that will render a list of Settings and a button. This last component will hold the values of all Settings. Finally, each time the value of a Setting Component Change, we update the list. Checkout a sample working app here.
App Component
export default class App extends PureComponent {
state = {};
onSettingChange = (settingId, setting) => {
this.setState(prevState => ({
...prevState,
[settingId]: setting
}));
};
onGetSettingValues = () => {
console.log(this.state);
};
render() {
return (
<Fragment>
<Setting id="setting1" onChange={this.onSettingChange} />
<Setting id="setting2" onChange={this.onSettingChange} />
<button onClick={this.onGetSettingValues}>Get All Values</button>
</Fragment>
);
}
}
Setting Component
import React, { PureComponent, Fragment } from "react";
import ChildSwitch from "./ChildSwitch";
import ParentSwitch from "./ParentSwitch";
export default class Setting extends PureComponent {
state = {
parentVal: "disabled",
switch1Val: "enabled",
switch2Val: "disabled"
};
componentDidMount() {
this.setParentSwitchValue();
}
setChildSwitchValue = (whichSwitch, selected) => {
this.setState(
prevState => ({ ...prevState, [whichSwitch]: selected }),
this.setParentSwitchValue
);
};
handleChange = () => {
const { id, onChange } = this.props;
onChange(id, this.state);
};
setParentSwitchValue = () => {
const { switch1Val, switch2Val } = this.state;
const switchStates = [switch1Val, switch2Val];
let parent = "pending";
if (switchStates.every(val => val === "enabled")) {
parent = "enabled";
}
if (switchStates.every(val => val === "disabled")) {
parent = "disabled";
}
this.setState(
prevState => ({ ...prevState, parentVal: parent }),
this.handleChange
);
};
render() {
const { parentVal, switch1Val, switch2Val } = this.state;
return (
<Fragment>
<div className="boxed">
Parent Setting 1
<ParentSwitch
parentSwitch={parentVal}
onSelect={this.setParentSwitchValue}
/>
Setting 1:
<ChildSwitch
switchName={"switch1Val"}
selected={switch1Val}
onSelect={this.setChildSwitchValue}
/>
Setting 2:
<ChildSwitch
switchName={"switch2Val"}
selected={switch2Val}
onSelect={this.setChildSwitchValue}
/>
</div>
</Fragment>
);
}
}
Put all your states into a single context hook.
const SettingsContext = createContext({state1, state2/* all your states in here*/);
You'll then wrap the whole thing into this context as such:
<SettingsContext.Provider>
<App/>
</SettingsContext.Provider>
Now you can access the state in any of the children, parents etc. I suggest however not storing things like "disabled", "enabled" as strings, but rather store states as { enabled: true, pending: false}

Trying to get my delete button to work on a React Component

I'm working on my First project with React, I have an App and a ToDo. I am defining a deleteToDo method and I want the method to call this.setState() and pass it a new array that doesn't have the to-do item being deleted with the use of the .filter() array method. I don't want to alter the code to much or introduce more complexity. In essence I would like to keep it as straight forward as possible. I am still a beginner with React so this has been a big learning process. I feel that I am close.
This is the main app
import React, { Component } from 'react';
import './App.css';
import ToDo from './components/ToDo.js';
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: [
{ description: 'Walk the cat', isCompleted: true },
{ description: 'Throw the dishes away', isCompleted: false },
{ description: 'Buy new dishes', isCompleted: false }
],
newTodoDescription: ''
};
}
deleteToDo(index) {
const todos = this.state.todos.slice();
const todo = todos[index];
todo.deleteToDo = this.state.filter(index);
this.setState({ todos: todos });
}
handleChange(e) {
this.setState({ newTodoDescription: e.target.value })
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.newTodoDescription) { return }
const newTodo = { description: this.state.newTodoDescription, isCompleted: false };
this.setState({ todos: [...this.state.todos, newTodo], newTodoDescription: '' });
}
toggleComplete(index) {
const todos = this.state.todos.slice();
const todo = todos[index];
todo.isCompleted = todo.isCompleted ? false : true;
this.setState({ todos: todos });
}
render() {
return (
<div className="App">
<ul>
{ this.state.todos.map( (todo, index) =>
<ToDo key={ index } description={ todo.description } isCompleted={ todo.isCompleted } toggleComplete={ this.toggleComplete } deleteToDo={ this.deleteToDo } />
)}
</ul>
<form onSubmit={ (e) => this.handleSubmit(e) }>
<input type="text" value={ this.state.newTodoDescription } onChange={ (e) => this.handleChange(e) } />
<input type="submit" />
</form>
</div>
);
}
}
export default App;
And this the ToDo aspect
import React, { Component } from 'react';
class ToDo extends Component {
render() {
return (
<li>
<button type="button" onClick={ this.props.deleteTodo} > delete </button>
<input type="checkbox" checked={ this.props.isCompleted } onChange={ this.props.toggleComplete } />
<span>{ this.props.description }</span>
</li>
);
}
}
export default ToDo;
You slice and array without the index, that's may be why your delete not work
deleteToDo(index) {
const todos = this.state.todos.slice(index, 1);
this.setState({ todos: todos });
}
1) You need to bind your deleteToDo method in the constructor
this.deleteToDo = this.deleteToDo.bind(this);
2) You need to set a new property on the component that is the same as its index.
<ToDo
key={index}
id={index}
description={ todo.description }
// ...
/>
3) Then you can pass that index as the argument to deleteToDo (making sure you spell the method name correctly).
<button
type="button"
onClick={() => this.props.deleteToDo(this.props.index)}
>Delete
</button>
4) Finally, you can strip down your deleteToDo method to the following:
deleteToDo(index) {
// Return a new array that doesn't
// have a row with a matching index
const todos = this.state.todos.filter((el, i) => i !== index);
this.setState({ todos });
}
Here's a working version.

setState() doesn't update value

I'm trying to update state of my component and it's not working. I have Main page container component => nested Navbar container component => nested NavItem UI component. Also on Main page I have AddNavItem container component which should add item to Navbar. It looks like this:
Main
|
|--NavBar
| |
| |--NavItem
|
|--AddNavItem
This is my Main page code:
import React, { Component } from 'react';
import Navbar from '../nav/Navbar'
import AddNavItem from '../fields/AddNavItem'
class Main extends Component {
state = {
items: [
{id: 1, name: 'Услуги', link: 'services'},
{id: 2, name: 'Цены', link: 'prices'},
{id: 3, name: 'Как это работает?', link: 'works'},
]
}
addNavItem = (item) => {
this.setState((state) => {
let newItems = [...state.items];
newItems.unshift(item)
console.log(newItems);
return {
items: newItems
}
});
}
render() {
return (
<div>
<Navbar items={ this.state.items }/>
<AddNavItem addNavItem={ this.addNavItem }/>
</div>
);
}
}
export default Main;
The problem is that I always get old array with 3 initial obj even after addNavItem is firing. <Navbar /> still gets array with 3 element. I have read about async setState and makes as describe in doc https://reactjs.org/docs/faq-state.html What have I doing wrong?
UPD: I changed code (unshift) to return array, not a length of the array. Console log shows me that I get new array with 4 obj
UPD: My complete code for all components:
Navbar
import React, { Component } from 'react';
import NavItem from './NavItem';
class Navbar extends Component {
state = {
items: this.props.items,
}
render() {
return (
<div className="centered navbar grey">
<h2>MyReact</h2>
<ul>
<NavItem items={ this.state.items }/>
</ul>
</div>
);
};
}
export default Navbar;
NavItem:
import React from 'react';
const NavItem = ({ items }) => {
const menuItemList = items.map((item) => {
return (
<li key={item.id}>
{ item.name }
</li>
);
})
return (
<div>
{ menuItemList }
</div>
)
}
export default NavItem;
AddNavItem:
import React, { Component } from 'react';
class AddNavItem extends Component {
state = {
id: Math.random(),
name: null,
link: null
}
handleInput = (e) => {
this.setState({
[e.target.id]: e.target.value,
});
}
handleSubmit = (e) => {
e.preventDefault();
this.props.addNavItem(this.state);
}
render() {
return (
<div className="centered flex-column-centered">
<form onSubmit={ this.handleSubmit }>
<h4 className="labelField">Название раздела:</h4>
<input
className="inputField"
type="text"
id="name"
placeholder="укажите название"
onChange={ this.handleInput } />
<h4 className="labelField">URL:</h4>
<input
className="inputField"
type="text"
id="link"
placeholder="укажите ссылку"
onChange={ this.handleInput } />
<button className="submitBtn">Добавить</button>
</form>
</div>
);
}
}
export default AddNavItem;
According to Mozilla docs
The unshift() method adds one or more elements to the beginning of an array and returns the new length of the array.
So when you try to change your state using this, it's returning the length of the array instead of the new array you're trying to update the state to. On top of that, this method is mutable as you are modifying the original array instead of returning a new copy of it. I would suggest changing your code to use the array.prototype.concat() method instead as it keeps your state immutable as it returns a new array instead of modifying the original array.
Try changing your method to this instead.
addNavItem = (item) => {
this.setState({ items: this.state.items.concat(item) });
}
Edit:
If you are using es6, you can use the spread syntax which also returns a new copy of the array.
addNavItem = (item) => {
this.setState({ items: [...this.state.items, item] });
}
Edit 2:
In your Navbar component, you're setting this.props.items to state when it initializes and then you don't update your state when this.props.items change.
You don't need state for this component, I would change your NavBar component to look like this:
import React from 'react';
import NavItem from './NavItem';
const Navbar = (props) => {
return (
<div className="centered navbar grey">
<h2>MyReact</h2>
<ul>
<NavItem items={ props.items }/>
</ul>
</div>
);
}
export default Navbar;
Edit 3:
If you want to keep your items inside state in your NavBar component, then you need to watch for updates being made to the items props on that component.
import React, { Component } from 'react';
import NavItem from './NavItem';
class Navbar extends Component {
state = {
items: this.props.items,
}
componentDidUpdate(prevProps) {
if (this.props.items!== prevProps.items) {
this.setState({ items: this.props.items });
}
}
render() {
return (
<div className="centered navbar grey">
<h2>MyReact</h2>
<ul>
<NavItem items={ this.state.items }/>
</ul>
</div>
);
};
}
export default Navbar;
let arr = [3,4,5]
console.log(arr.unshift(3,5))
addNavItem = (item) => {
let newItems = [...this.state.items];
newItems.unshift(item)
this.setState({
items: newItems
}
});
}
Now you are updating the array and adding the elements to the begining of it, which i assume you wanted and is why you picked upshift. you are then setting the sate equal to the updated array you have.
addNavItem = (item) => {
this.setState((prevState) => {items: [...prevState.items, item]})
}
This should work.

React state keep old state

I have some issue in React that seems to keep last or old state.
I have a parent component called MyLists.js that contain a loop function where I rendered child component called Item.js
{
this.state.listProducts.map(d =>
<Item data={d} />
)}
And in my Item.js component I set state in constructor :
this.state = { showFullDescription: false }
The variable "showFullDescription" allows me to see the entire description of a product. Now I have for example 2 products and all states "showFullDescription" are set to false so :
Product 1 => (showFullDescription = false)
Product 2 => (showFullDescription = false)
Next, I show full description for Product 2 by clicking a button and I set state to true so Product 2 => (showFullDescription = true)
The problem is when I add another product, let's call it "Product 3", the full description of "Product 3" is directly shown and for "Product 2" it is hidden. It seems that last state is reflected on "Product 3".
I am really sorry for my english, it's not my native language
Here is full source code :
MyLists.js
import React, { Component } from 'react';
import ProductService from '../../../../services/ProductService';
import Item from './Item';
class MyLists extends Component {
constructor(props) {
super(props);
this.state = {
products: []
}
this.productService = new ProductService();
this.productService.getAllProducts().then((res) => {
this.setState({
products: res
})
});
}
addProduct(data){
this.productService.addProduct(data).then((res) => {
var arr = this.state.products;
arr.push(res);
this.setState({
products: arr
})
})
}
render() {
return (
<div>
{
this.state.products.map(d =>
<Item data={d} />
)}
</div>
)
}
}
export default MyLists;
Item.js
import React, { Component } from 'react';
import Truncate from 'react-truncate';
class Item extends Component {
constructor(props) {
super(props);
this.state = {
showFullDescription: false
}
}
render() {
return (
<div>
<h2>{this.props.data.title}</h2>
{
!this.state.showFullDescription &&
<Truncate lines={10} ellipsis={<a className="btn btn-primary read-more-btn" onClick={() => this.setState({showFullDescription: true})}>Show More</a>}>
{this.props.data.description}
</Truncate>
)}
{
this.state.showFullDescription &&
<span>
{this.props.data.description}
</span>
}
</div>
)
}
}
export default Item;
You have some syntax problems and missing && for !this.state.showFullDescription.
I've slightly changed the component and use ternary operator to render conditionally. It is a little bit ugly right now, the logic can be written outside of the render. Also, I suggest you to use a linter if you are not using.
MyLists.js
class MyLists extends React.Component {
state = {
products: [
{ id: 1, description: "Foooooooooooooooooooooooooooooooooooooooooo", title: "first" },
{ id: 2, description: "Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrr", title: "second" },
{ id: 3, description: "Baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz", title: "third" },
]
}
render() {
return (
<div>
{
this.state.products.map(d =>
<Item data={d} />
)}
</div>
)
}
}
Item.js
class Item extends React.Component {
state = {
showFullDescription: false,
}
render() {
return (
<div>
<h2>{this.props.data.title}</h2>
{ !this.state.showFullDescription
?
<Truncate lines={3} ellipsis={<span>... <button onClick={() => this.setState({showFullDescription: true})}>Read More</button></span>}>
{this.props.data.description}
</Truncate>
:
<span>
{this.props.data.description}
</span>
}
</div>
)
}
}
Here is working sandbox: https://codesandbox.io/s/x24r7k3r9p
You should try mapping in the second component as:
class Item extends React.Component {
state = {
showFullDescription: false,
}
render() {
return (
<div>
{this.props..data.map(data=>
<h2>{this.props.data.title}</h2>
{ !this.state.showFullDescription
?
<Truncate lines={3} ellipsis={<span>... <button onClick={() =>
this.setState({showFullDescription: true})}>Read More</button>
</span>}>
{this.props.data.description}
</Truncate>
:
<span>
{this.props.data.description}
</span>)}
}
</div>
)
}
}
You should have a 'key' property (with unique value) in 'Item' - No warnings about it in console?

Categories

Resources