I'm having issues with deleting elements in react-flow via a button.
I can delete elements fine using Backspace but the button only works for the first delete and after that it brings back the deleted node.
New to using react-flow and can't put my finger on the problem here. Is the state not getting changed some how?
Below is the code I use for react flow
CodeSandbox here.
import React, { useState, useCallback, useEffect } from "react";
import ReactFlow, {
removeElements,
addEdge,
Background,
} from "react-flow-renderer";
const onLoad = (reactFlowInstance) => {
reactFlowInstance.fitView();
console.log(reactFlowInstance.getElements());
};
const StackFlow = () => {
const initialElements = [
{
id: "0",
position: { x: 0, y: -100 },
sourcePosition: "bottom",
style: {
width: 100,
fontSize: 11,
color: "white",
background: "#6ec9c0",
},
data: {
label: (
<>
<button
className="w-md h-md border-2 border-black p-2"
onClick={() =>
remModelData("0")
}
>
Del
</button> <br /> <br />
<strong>Models</strong>
</>
),
},
},
{
id: "1",
position: { x: 100, y: 50 },
sourcePosition: "bottom",
targetPosition: "top",
data: {
label: (
<>
<button
className="w-md h-md border-2 border-black p-2"
onClick={() =>
remModelData("1")
}
>
Del
</button> <br /> <br />
Model: <strong>1</strong> <br />
ID: 1
</>
),
},
},
{
id: "2",
position: { x: 150, y: 250 },
sourcePosition: "bottom",
targetPosition: "top",
data: {
label: (
<>
<button
className="w-md h-md border-2 border-black p-2"
onClick={() =>
remModelData("2")
}
>
Del
</button> <br /> <br />
Model 1: <strong>subModel1</strong> <br />
ID: 2
</>
),
},
},
{
id: "3",
position: { x: 250, y: 250 },
sourcePosition: "bottom",
targetPosition: "top",
data: {
label: (
<>
<button
className="w-md h-md border-2 border-black p-2"
onClick={() =>
remModelData("3")
}
>
Del
</button> <br /> <br />
Model 1: <strong>subModel2</strong> <br />
ID: 3
</>
),
},
},
{
id: "0-1",
type: "step",
source: "0",
target: "1"
},
{
id: "1-2",
type: "step",
source: "1",
target: "2"
},
{
id: "1-3",
type: "step",
source: "1",
target: "3"
},
];
const [elements, setElements] = useState(initialElements);
const onElementsRemove = useCallback(
(elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els)),
[]
);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const [reactflowInstance, setReactflowInstance] = useState(null);
useEffect(() => {
if (reactflowInstance && elements.length > 0) {
reactflowInstance.fitView();
}
}, [reactflowInstance, elements.length]);
const remModelData = useCallback((id) => {
let arr = elements
var index = arr.indexOf(id);
if (index > -1) {
arr.splice(index, 1);
}
arr = arr.filter(function (obj) {
return obj.id !== id;
});
console.log(arr);
setElements(arr);
}, []);
return (
<ReactFlow
elements={elements}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
onLoad={onLoad}
snapToGrid={true}
snapGrid={[15, 15]}
>
<Background color="#aaa" gap={16} />
</ReactFlow>
);
};
function Home() {
return (
<>
<div className="w-full mx-auto justify-center items-center flex">
<div
className="flex mt-10 flex-row items-center content-center justify-center max-h-5xl max-w-5xl py-2"
style={{ flex: 1, width: 1000, height: 800, borderWidth: 2 }}
>
<StackFlow />
</div>
</div>
</>
);
}
export default Home;
I was able to accomplish the end result I wanted by creating this function:
const deleteNode = (id) => {
setElements((els) => removeElements([elements[id]], els));
};
And passing this into the OnClick:
onClick={() => deleteNode(0)}
Changing 0 for what ever index the element you wish to remove from the array is
As from version 10 Elements has been replaced with Nodes and Edges.
I could achieve the following using the function below.
const deleteNodeById = (id) => {
flowInstance.setNodes((nds) => nds.filter((node) => node.id !== id))
}
And passing this function to my delete button (In my case mui delete icon)
<DeleteOutlined
onClick={() => deleteNodeById(data.id)}
style={{ color: '#FF0000' }}
/>
As of version 11.2 onwards, you can use
reactFlowInstance.deleteElements({ nodes: nodesToDelete, edges: edgesToDelete });
The advantage is that method will fire "onNodesDelete" & "onEdgesDelete" events so that you can reuse your handlers.
Recall that these events are also fired if you press the "backspace" button.
Related
what I try to do is to have the same display as this picture :
So in my menu the plant type (Type of plant1) is displayed above a gray bar and when you click on the down chevron then you can see all the plants name, related to this type, with checkboxes on left, by default there will be all checked. And the blue rectangle indicates the number of plants that have been selected.
How can I do that, which package can help me in REACT?
Here my plants.json :
{
"plants_type": [
{
"_id_type": "1",
"name_type": "Type of plant1",
"plants": [
{
"name": "Plant1.1",
"_id": "2"
},
{
"name": "Plant1.2",
"_id": "3"
}
]
},
{
"_id_type": "4",
"name_type": "Type of plant2",
"plants": [
{
"name": "Plant2.1",
"_id": "5"
},
{
"name": "Plant2.2",
"_id": "6"
}
]
}
]
}
You can create a dropdown list on your own like below. I have added the logic of selecting items to the data itself.
You can keep a component called Category to keep a single state of the parent menu item. Whether it's open or not. Then iterate over the plants as checkbox inputs to make them selectable.
I have used a simple initialize function to make all the items selected initially. This should work as you expect. Add a console log of selectionMenu to see how selected property changes while toggling items.
Move the inline styles to CSS classes to make the code more clear.
const data = { plants_type: [ { _id_type: "1", name_type: "Type of plant1", plants: [ { name: "Plant1.1", _id: "2" }, { name: "Plant1.2", _id: "3" } ] }, { _id_type: "4", name_type: "Type of plant2", plants: [ { name: "Plant2.1", _id: "5" }, { name: "Plant2.2", _id: "6" } ] } ] };
const Category = ({ _id_type, name_type, plants, changeSelection }) => {
const [toggleState, setToggleState] = React.useState(false);
return (
<div key={_id_type}>
<div
style={{
cursor: "pointer",
userSelect: "none",
display: "flex",
margin: "2px",
backgroundColor: "lightgray"
}}
onClick={() => setToggleState((prev) => !prev)}
>
<div>{name_type}</div>
<div
style={{
backgroundColor: "blue",
color: "white",
padding: "0px 10px",
marginLeft: "auto"
}}
>
{plants.filter(({ selected }) => selected).length}
</div>
</div>
<div style={{ marginLeft: "10px" }}>
{toggleState &&
plants.map(({ name, _id, selected }) => (
<div key={_id}>
<input
key={_id}
type="checkbox"
value={name}
checked={selected}
onChange={(e) => changeSelection(_id_type, _id, e.target.value)}
/>
{name}
</div>
))}
</div>
</div>
);
};
const App = () => {
const initializeSelectionMenu = (data) => {
return data.map((item) => {
return {
...item,
plants: item.plants.map((plant) => ({ ...plant, selected: true }))
};
});
};
const [selectionMenu, setSelectionMenu] = React.useState(
initializeSelectionMenu(data.plants_type)
);
console.log(selectionMenu);
const changeSelection = (catId, itemId, value) => {
setSelectionMenu((prevSelectionMenu) =>
prevSelectionMenu.map((item) => {
if (item._id_type === catId) {
return {
...item,
plants: item.plants.map((plant) => {
if (plant._id === itemId) {
return { ...plant, selected: !plant.selected };
}
return plant;
})
};
}
return item;
})
);
};
return (
<div>
{selectionMenu.map((item) => (
<Category
{...item}
changeSelection={changeSelection}
key={item._id_type}
/>
))}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
I'm attempting to create a quantity filter based on color, size, or both. When I click the red color, for example, it displays the whole quantity of the red color, but if I press color red and size small, it displays the exact quantity I require. Is there a way to accomplish this?
This is what I mean.
When I select a color or a size, the quantity should be displayed. Also, there should not be a duplication of my error, since there are three red colors listed above the image.
Code
import React, { useState } from "react";
export default function ControlledRadios() {
const [qty, setQty] = useState(0);
const data = [
{
id: 1,
name: "Product A",
attributes: [
{
id: 1,
color: "Red",
size: "Small",
qty: 200,
},
{
id: 2,
color: "Red",
size: "Medium",
qty: 100,
},
{
id: 3,
color: "Red",
size: "Large",
qty: 300,
},
{
id: 4,
color: "Yellow",
size: "Small",
qty: 200,
},
{
id: 5,
color: "Yellow",
size: "Medium",
qty: 100,
},
{
id: 6,
color: "Yellow",
size: "Large",
qty: 300,
},
],
},
];
const handleChange = (event) => {
setQty(event.target.value);
};
return (
<>
<h1>Quantity: {qty}</h1>
<fieldset value={qty} onChange={(event) => handleChange(event)}>
<h3>Color:</h3>
{data?.map(({ attributes }) => {
return attributes.map(({ id, ...rest }) => (
<>
<label key={id}>
<input
type="radio"
name="schedule-weekly-option"
value={rest.qty}
/>
{rest.color}
</label>
<br />
</>
));
})}
<h3>Size:</h3>
{data?.map(({ attributes }) => {
return attributes.map(({ id, ...rest }) => (
<>
<label key={id}>
<input
type="radio"
name="schedule-weekly-option"
value={rest.qty}
/>
{rest.size}
</label>
<br />
</>
));
})}
</fieldset>
</>
);
}
As seen in the data value, I have multiple color and sizes goes something like this for example {color: "Red", Size: "Small", qty: 200} I have multiple red values, so right every red should be added so when I click the Red radio button it should display the quantity 600 because the quantity of all the red will be added. but if I press like color Red and size Small it should display 200.
PS: If possible can u not make duplicate of colors like I did 3 color red and yellow, to make it only 1 Red and 1 Yellow same goes with the size.
If you need anymore clarification you need or explanation please comment down below. Thanks
Phew! This should do the trick. The idea is to pass more data to your handleChange handleChange - see how I changed it? I grab the data straight out of the target element, which is not ideal, but works.
I didn't do the filtering for you, good luck with that :) Should be just adding a (granted, a fairly complex) .filter(...) to your .map(...).
document.onreadystatechange = () => {
const {useState} = React;
function ControlledRadios() {
const [qty, setQty] = useState(0);
const data = [
{
id: 1,
name: "Product A",
attributes: [
{
id: 1,
color: "Red",
size: "Small",
qty: 200,
},
{
id: 2,
color: "Red",
size: "Medium",
qty: 100,
},
{
id: 3,
color: "Red",
size: "Large",
qty: 300,
},
{
id: 4,
color: "Yellow",
size: "Small",
qty: 200,
},
{
id: 5,
color: "Yellow",
size: "Medium",
qty: 100,
},
{
id: 6,
color: "Yellow",
size: "Large",
qty: 999,
},
],
},
];
const handleChange = (event) => {
const id = event.target.value;
const targetAttribute = data[0].attributes.find(x => x.id == id);
if (event.target.name === "schedule-weekly-option-color") {
let sum = 0;
data[0].attributes.forEach((a) => {
if (a.color===targetAttribute.color) {
sum += a.qty;
}
});
setQty(sum);
} else {
let sum = 0;
data[0].attributes.forEach((a) => {
if (a.color===targetAttribute.color && a.size===targetAttribute.size) {
sum += a.qty;
}
});
setQty(sum);
}
};
return (
<React.Fragment>
<h1>Quantity: {qty}</h1>
<fieldset value={qty} onChange={(event) => handleChange(event)}>
<h3>Color:</h3>
{data.map(({ attributes }) => {
return attributes.map(a => (
<label key={a.id}>
<input
type="radio"
name="schedule-weekly-option-color"
value={a.id}
/>
{a.color}
</label>
));
})}
<h3>Size:</h3>
{data.map(item => {
return item.attributes.map(a => (
<label key={a.id}>
<input
type="radio"
name="schedule-weekly-option-size"
value={a.id}
/>
{a.size}
</label>
));
})}
</fieldset>
</React.Fragment>
);
}
ReactDOM.render(<ControlledRadios />, document.body);
};
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Here is my backend code
app.get("/sortedcustomers", (req, res) => {
db.query("SELECT * FROM customer_info ORDER BY contacted", (err, result) => {
if (err) {
console.log(err);
} else {
res.send(result);
}
});
});
which gives me data in this form:
[{"ID":1,"name":"Queen","email":"Queen#gmail.com","counts_of_visit":13,"latest_time_of_visit":"2021-03-12T12:08:23.000Z","contacted":"No"},{"ID":3,"name":"Alex","email":"Alex#gmail.com","counts_of_visit":7,"latest_time_of_visit":"2021-04-30T09:50:23.000Z","contacted":"No"},{"ID":2,"name":"Wayne","email":"Wayne#gmail.com","counts_of_visit":10,"latest_time_of_visit":"2021-04-30T09:50:23.000Z","contacted":"Yes"},{"ID":4,"name":"Jack","email":"Jack#gmail.com","counts_of_visit":3,"latest_time_of_visit":"2021-04-30T09:50:23.000Z","contacted":"Yes"}]
Then my frontend code:
function Home(props) {
const [customerList, setCustomerList] = useState([]); //store all that information of the database in a list
//make an axios request to get information from database
useEffect(() => {
Axios.get("http://localhost:3001/customers").then((response) => {
setCustomerList(response.data);
});
}, []);
const getSortedCustomerList = () => {
Axios.get("http://localhost:3001/sortedcustomers").then((response) => {
setCustomerList(response.data);
});
};
const updateCustomerContacted = (ID) => {
Axios.put("http://localhost:3001/update", {
contacted: newContacted,
ID: ID,
}).then((response) => {
setCustomerList(
customerList.map((val) => {
return val.ID == ID
? {
ID: val.ID,
name: val.name,
email: val.email,
counts_of_visit: val.counts_of_visit,
latest_time_of_visit: formatDatetime(val.latest_time_of_visit),
contacted: newContacted,
}
: val;
})
);
});
};
//function to format the datetime to correct format
const formatDatetime = (datetime) => {
const dateStr = new Date(datetime).toLocaleDateString("en-CA");
const timeStr = new Date(datetime).toLocaleTimeString();
return `${dateStr} ${timeStr}`;
};
const deleteCustomer = (ID) => {
Axios.delete(`http://localhost:3001/stats/delete/${ID}`).then(
(response) => {
setCustomerList(
customerList.filter((val) => {
return val.ID != ID;
})
);
}
);
};
//pagination
const [pageNumber, setPageNumber] = useState(0);
const customersPerPage = 5; //change this number according to desired number of rows in a page
const pagesVisited = pageNumber * customersPerPage;
const displayCustomers = customerList
.slice(pagesVisited, pagesVisited + customersPerPage)
.map((val, key) => {
const dateStr = new Date(val.latest_time_of_visit).toLocaleDateString(
"en-CA"
);
const timeStr = new Date(val.latest_time_of_visit).toLocaleTimeString();
const dateTime = `${dateStr} ${timeStr}`;
const my_serial = key + pageNumber * customersPerPage;
return (
<tr>
{/*}
<td>{val.ID}</td>
*/}
<td>{my_serial + 1}</td>
<td>{val.name}</td>
<td>{val.email}</td>
<td>{val.counts_of_visit}</td>
<td>{dateTime}</td>
<td>{val.contacted}</td>
<td>
<select
onChange={(event) => {
setNewContacted(event.target.value);
}}
>
<option value="" selected disabled hidden>
Select Yes/No
</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<button
className="btn btn-primary"
onClick={() => {
updateCustomerContacted(val.ID);
}}
>
Update
</button>
</td>
<td>
<button
className="btn btn-danger"
onClick={() => {
deleteCustomer(val.ID);
}}
>
Delete
</button>
</td>
</tr>
);
});
//to account for the fact that total number of customers cannot be divided equally among the pages
const pageCount = Math.ceil(customerList.length / customersPerPage);
//page change
const changePage = ({ selected }) => {
setPageNumber(selected);
};
//update contacted column
const [newContacted, setNewContacted] = useState(0);
//export to csv function
const DataSet = [
{
columns: [
{
title: "S/N",
style: { font: { sz: "18", bold: true } },
width: { wpx: 125 },
}, // width in pixels
{
title: "Customer Information",
style: { font: { sz: "18", bold: true } },
width: { wpx: 250 },
}, // width in pixels
{
title: "Customer Email",
style: { font: { sz: "18", bold: true } },
width: { wpx: 250 },
}, // width in pixels
{
title: "Counts of Visit",
style: { font: { sz: "18", bold: true } },
width: { wpx: 175 },
}, // width in pixels
{
title: "Latest Time of Visit",
style: { font: { sz: "18", bold: true } },
width: { wpx: 250 },
}, // width in pixels
{
title: "Contacted?",
style: { font: { sz: "18", bold: true } },
width: { wpx: 250 },
}, // width in pixels
],
data: customerList.map((val, key) => [
{ value: key + 1, style: { font: { sz: "14" } } },
{ value: val.name, style: { font: { sz: "14" } } },
{ value: val.email, style: { font: { sz: "14" } } },
{ value: val.counts_of_visit, style: { font: { sz: "14" } } },
{
value: formatDatetime(val.latest_time_of_visit),
style: { font: { sz: "14" } },
},
{ value: val.contacted, style: { font: { sz: "14" } } },
]),
},
];
return (
<div>
<GridItem xs={12} sm={12} md={12}>
<Card>
<CardHeader color="warning">
<h4 className={classes.cardTitleWhite}>Customer Information</h4>
<p className={classes.cardCategoryWhite}></p>
</CardHeader>
<CardBody>
<div className="dashboardcontainer">
<div className="container"></div>
<table className="customertable">
<thead>
<tr>
{/*}
<th>S/N</th>
*/}
<th>S/N</th>
<th>Customer Name</th>
<th>Customer Email</th>
<th>Counts of Visit</th>
<th>Latest Time of Visit</th>
<th onClick={getSortedCustomerList}>Contacted?</th>
<th>Edit Contacted</th>
<th>Action</th>
</tr>
</thead>
<tbody>{displayCustomers}</tbody>
</table>
<ReactPaginate
previousLabel={"Previous"}
nextLabel={"Next"}
pageCount={pageCount}
onPageChange={changePage}
containerClassName={"paginationBttns"}
pageLinkClassName={"paginationNumber"}
previousLinkClassName={"previousBttn"}
nextLinkClassName={"nextBttn"}
disabledClassName={"paginationDisabled"}
activeClassName={"paginationActive"}
/>
<ExcelFile
filename="Customer Information"
element={
<button
type="button"
className="btn btn-success float-right m-3"
>
Export to Excel
</button>
}
>
<ExcelSheet
dataSet={DataSet}
name="Customer Information Report"
></ExcelSheet>
</ExcelFile>
</div>
</CardBody>
</Card>
</GridItem>
</GridContainer>
</div>
);
}
But the thing about my frontend is that when I click on the "Contacted?" header column it does show the sorted data, but how do I make it show the reverse sorted list then the normal unsorted customer list on the last click. So first click sorted list works, but second click sorted reverse list doesn't work and 3rd click unsorted list doesn't work.
So, basically, I have this crud table, when I click contacted column, it sorts itself accordingly, but when I click again it does not sort in reverse order, then when I click again it does not go back to unsorted order, how to solve this?
try
customerList.sort(function(a, b) {
return b - a;
})
,or, if that doesn't work:
customerList.reverse()
As far as I can see ant design's table currently doesn't ship with a specific numeric search, where I can return results within a specific range, example >10 or <=50.
Given the below example:
codesandbox
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Table, Input, Button, Icon } from 'antd';
import Highlighter from 'react-highlight-words';
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Joe Black',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Jim Green',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
age: 32,
address: 'London No. 2 Lake Park',
},
];
class App extends React.Component {
state = {
searchText: '',
};
getColumnSearchProps = dataIndex => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
ref={node => {
this.searchInput = node;
}}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm)}
icon="search"
size="small"
style={{ width: 90, marginRight: 8 }}
>
Search
</Button>
<Button onClick={() => this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
Reset
</Button>
</div>
),
filterIcon: filtered => (
<Icon type="search" style={{ color: filtered ? '#1890ff' : undefined }} />
),
onFilter: (value, record) =>
record[dataIndex]
.toString()
.toLowerCase()
.includes(value.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
},
render: text => (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text.toString()}
/>
),
});
handleSearch = (selectedKeys, confirm) => {
confirm();
console.log(selectedKeys);
this.setState({ searchText: selectedKeys[0] });
};
handleReset = clearFilters => {
clearFilters();
this.setState({ searchText: '' });
};
render() {
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: '30%',
...this.getColumnSearchProps('name'),
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
width: '20%',
...this.getColumnSearchProps('age'),
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
...this.getColumnSearchProps('address'),
},
];
return <Table columns={columns} dataSource={data} />;
}
}
ReactDOM.render(<App />, document.getElementById('container'));
Let's look at the age column, if we specify an exact age, exact results will be returned. On the input element when the value is keyed in, on either enter press or onClick, handleSearch is triggered, handleSearch then sets the react state, then the component is re-rendered, all basic react functionality.
I am unsure where is the logic that sets what supposed to be returned so unsure where and how should I implement custom logic to check for a specific range of numbers rather than an exact number. Any ideas?
Alternatively, I checked if a numeric search/filter already exists for ant-design, but I couldn't find anything.
For further reference, see ant-designs table documentation
You can render whatever filter you like, for example using Slider and InputNumber combination:
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm }) => (
<div style={{ padding: 8 }}>
<Row
type="flex"
gutter={10}
style={{ marginBottom: 8, alignItems: "center" }}
>
<Col>Range:</Col>
<Col>
<InputNumber
value={this.state.left}
onChange={e => {
this.setState({ left: e });
setSelectedKeys(data.filter(d => e <= d.age).map(d => d.key));
}}
/>
</Col>
<Col>
<InputNumber
value={this.state.right}
onChange={e => {
this.setState({ right: e });
setSelectedKeys(data.filter(d => d.age <= e).map(d => d.key));
}}
/>
</Col>
</Row>
<Row>
<Slider
range
value={[this.state.left, this.state.right]}
onChange={e => this.setState({ left: e[0], right: e[1] })}
/>
</Row>
<Row>
<Button
type="primary"
block
size="small"
onClick={() => {
this.handleSearchAge(selectedKeys, confirm);
setSelectedKeys(
data
.filter(
d => this.state.left <= d.age && d.age <= this.state.right
)
.map(d => d.key)
);
}}
>
Confirm
</Button>
</Row>
</div>
);
i wonder if you still have the example, the link is broke
I'm a newbie trying to use React Spring in my React (16.8) project. I made a little carousel which works, but I want to add a credit at the bottom of each slide which should stagger in. A credit consist of two items and the second should animate in a tad slower than the first.
For this I want to use Trail but while the contents of the Trail renders, the animation does not fire.
This is my code so far:
const slides = [
{
id: 0,
desktopImage: "http://lorempixel.com/400/200/",
title: "foo",
studio: "bar"
},
{
id: 1,
desktopImage: "http://lorempixel.com/400/200/",
title: "foo",
studio: "bar"
},
{
id: 2,
desktopImage: "http://lorempixel.com/400/200/",
title: "foo",
studio: "bar"
}
];
const [slideIndex, set] = useState(0);
useEffect(
() =>
void setInterval(() => set(state => (state + 1) % slides.length), 4000),
[]
);
const transitions = useTransition(slides[slideIndex], item => item.id, {
from: { opacity: 0, left: -10 },
enter: { opacity: 1, left: -100 },
leave: { opacity: 1, left: -100 },
config: { friction: 25, duration: 4000 }
});
return (
<div className="header">
{transitions.map(({ item, props, key }) => {
let bgImg = item.desktopImage;
const creditArray = [item.title, item.studio];
return (
<div key={key}>
<animated.div
className="bg"
style={{ ...props, backgroundImage: `url(${bgImg})` }}
/>
<div className="imageCredit">
{
<Trail
key={key}
items={creditArray}
keys={key}
from={{ opacity: 0, transform: "translate3d(-100, 0, 0)" }}
to={{ opacity: 1, transform: "translate3d(0, 0, 0)" }}
>
{item => props => <div className="h4">{item}</div>}
</Trail>
}
</div>
</div>
);
})}
</div>
);
Figured it out, I forgot to pass downn the actual style down to the rendered element.
so instead of :
<Trail
key={key}
items={creditArray}
keys={key}
from={{ opacity: 0, transform: "translate3d(-100, 0, 0)" }}
to={{ opacity: 1, transform: "translate3d(0, 0, 0)" }}>
{item => props => <div className="h4">{item}</div>}
</Trail>
I needed to do:
<Trail
items={creditArray}
keys={item => item + key}
from={{opacity: 0, transform: 'translateX(100px)'}}
to={{opacity: 1, transform: 'translateX(0)'}}>
{item => style => (
<animated.div style={{ ...style }} className="h4">
{item}
</animated.div>
)}
</Trail>