I am working on a product feedback app (with react) for my portfolio and came across an unexpected problem. The issue takes place in my SuggestionDetails component where I am getting the current id with useParams and filtering out the current product based on that id. Everything works and renders perfectly fine with the pre-existing suggestions array, but the problem starts when I try to render a new suggestion that I have created and added to the array.
This is how I am getting the current suggestion:
// I am getting the suggestions array through props
const { id } = useParams();
const [suggestion, setSuggestion] = useState(() => {
const currentSuggestion =
suggestions &&
suggestions.filter((suggestion) =>
suggestion.id === parseInt(id) ? suggestion : null
);
return currentSuggestion;
});
This is what the return value of the current suggestion should be (the new suggestion is still not created here):
Here when I try to filted out the new suggestion (the last element) I get an empty array:
I am still kind of new to this stuff and dont understand why this is happening. I have not added the code where I am creating a new suggestion and adding it to the current state, but I don't think the issue is there since it has clearly been created and added to current list of suggestion requests. Any information on this would be greatly appreciated, thank you.
The problem was that I was using parseInt instead of parseFloat to parse the id generated by Math.random()
Related
I'm working on a form view with a lot of fields being displayed dynamically given some other parameters. I have this very long form divided in different components.
In this part of the form, the user can define as many tasks as needed, and for each task there are some fields and buttons displayed, which are all managed on an object array inside the component's state (each task is an object included in the array).
I'm showing this by mapping the tasks array inside the render and everything is working fine, except for one thing, which are some toggle buttons. This is the code for each toggle button:
<Toggle label='¿Requiere registro?' data-key={e.numero} inlineLabel onText=' ' offText=' ' checked={e.regBool} onChange={this.checkRegistro} />
And this is the code of the function that is called:
public checkRegistro = (ev, checked: boolean) => {
const temp = checked;
ev.target.dataset ? console.log(ev.target.dataset.key) : console.log('no toma key');
const numero = ev.target.dataset ? ev.target.dataset.key : '1';
var arr = [...this.state.tareas];
const index = arr.map((e) => {return e.numero;}).indexOf(parseInt(numero));
if(index !== -1){
arr[index].regBool = temp;
this.setState({tareas: [...arr]})
console.log(arr[index].regBool);
}
}
As you can see, I specified data-key so I could access to the correct task (this.state.tareas) given the number of the task (tareas[index].numero).
The problem here is, sometimes (just sometimes) ev.target.dataset.key returns undefined. I try pressing the same toggle a couple of times, but only after I stop pressing it and wait a second it returns the correct value again
I suppose it's because as there is much to render, it doesn't get to specify the correct value on the data-key all the time, but I have no idea on how to make it work consistently. I've thought on separating it on another component being called for each task, but I'm not quite sure how that could help.
Any idea is well received, if you need more information you could also let me know. Please consider this is my first post here.
Thank you!!
This is a difficult one to explain so I will do my best!
My Goal
I have been learning React and decided to try build a Todo List App from scratch. I wanted to implement a "push notification" system, which when you say mark a todo as complete it will pop up in the bottom left corner saying for example "walk the dog has been updated". Then after a few seconds or so it will be removed from the UI.
Fairly simple Goal, and for the most part I have got it working... BUT... if you quickly mark a few todos as complete they will get removed from the UI and then get re-rendered back in!
I have tried as many different ways of removing items from state as I can think of and even changing where the component is pulled in etc.
This is probably a noobie question, but I am still learning!
Here is a link to a code sandbox, best way I could think of to show where I am at:
Alert Component State/Parent
https://codesandbox.io/s/runtime-night-h4czf?file=/src/components/layout/PageContainer.js
Alert Component
https://codesandbox.io/s/runtime-night-h4czf?file=/src/components/parts/Alert.js
Any help much appreciated!
When you call a set function to update state, it will update from the last rendered value. If you want it to update from the last set value, you need to pass the update function instead of just the new values.
For instance, you can change your setTodos in your markComplete function to something like this.
setTodos(todos => todos.map((todo) => {
if (id === todo.id) {
todo = {
...todo,
complete: !todo.complete,
};
}
return todo;
}));
https://codesandbox.io/s/jovial-yalow-yd0jz
If asynchronous events are happening, the value in the scope of the executed event handler might be out of date.
When updating lists of values, use the updating method which receives the previous state, for example
setAlerts(previousAlerts => {
const newAlerts = (build new alerts from prev alerts);
return newAlerts;
});
instead of directly using the alerts you got from useState.
In the PageContainer.js, modify this function
const removeAlert = (id) => {
setAlerts(alerts.filter((alert) => alert.id !== id));
};
to this
const removeAlert = (id) => {
setAlerts(prev => prev.filter((alert) => alert.id !== id));
};
This will also fix the issue when unchecking completed todos at high speed
UPDATE: The problem was my initial state is an empty array, so for some reason it was only a problem when trying to destructure, but I change const lastMessage = messages.slice(-1)[0]; to const lastMessage = messages.slice(-1)[0] || {}; per some advice from someone on another platform, and all is good. My fault and I should've seen it, but was thrown off by reassignment working out just fine. Thank you for the help. I'd vote on your comments and answers, but my rep is too low. You are appreciated!
So I'm building a MERN based chat app with Redux. I'm trying to pull out data from the last message in my DB, and then pass that data as props to a component in React. The problem I'm encountering is that when trying to destructure the original const lastMessage, it (lastMessage) shows undefined. Here's what I'm doing:
1) Take the original messages prop out of state, that has an array of
message objects.
2) Use messages.slice(-1)[0] to assign the last object in the array to const
lastMessage.
3) Then what I WANT to do is destructure lastMessage to pull out the
data that I want (text and created), which will be passed down to
another component. But if I try this, I get the 'lastMessage is
undefined' error. See example below:
export const UserList = props => {
const { members, messages } = props;
const lastMessage = messages.slice(-1)[0];
const { text, date } = lastMessage;
console.log(text, date);
Error Undefined Here you can see the error that I'm encountering when trying to destructure. Also, I think it's worth noting that I tried destructuring directly from messages.slice(-1)[0] like this: const { text, created } = messages.slice(-1)[0] but that didn't work, same error. That is why I wondered if i needed to make a new const first, for some reason that maybe I was missing, like maybe a delay in the .slice(-1)[0] or something that was making it undefined when trying to pull out the data.
If I simply reassign it as I did in the code below, then it works fine and I can console log the data and it's all there. No errors or issues, so I know it's not a state mapping issue. Everything shows up as expected in state or in console log. What am I missing here?
export const UserList = props => {
const { members, messages } = props;
const lastMessage = messages.slice(-1)[0];
const example = lastMessage;
console.log(example);
Console Log of example const
You can also see this screenshot that shows when I simply reassign a new const example = lastMessage and, then console log that new example const.
Current state
Here's a screenshot of my current state if it helps anyone see the whole picture a bit better.
Thank you all in advance for any help you can offer.
I think is because is really empty, what if you first check if messages is not empty like:
if (messages) {
...
messages.slice(-1)[0]
...
}
My question is just about idea and creativity of you.
I have react component that is getting information from SQL database:
const [offers,setOffers] = useState([])
useEffect(()=>{
axios.get(`http://localhost:8085/incoming`)
.then(res=>{
setOffers(res.data.recordset)
})
.catch(error=>console.log(error))},[])
just when page is loaded.
In JSX I put one function that is filling my table:
<tbody className="table-hover">
{OfferItem(offers)}
</tbody>
The function is:
const OfferItem = (array)=>{
if(array!==undefined){
return array.map((item,index)=>{
return <IncomingOffer singleitem={item} index={index+1} key={item.Number}/>
})
}}
So far so good but I want to have input field that is providing dynamic search and re-rendering. So I put:
<label>Относно:</label><input onChange={searchAbout} />
And created my function:
const searchAbout = (e)=>{
e.preventDefault(e)
const string = e.target.value.toUpperCase()
const res = offers.filter(el=>Object.values(el).some(val=>val.toUpperCase().includes(string)))
setOffers(res)
}
In the way it is wrote it is working when typing in input field but as you see it is completely filtering the array and I am loosing all other items in it. So I was wondering for a way that I am filtering and re-rendering items but for example when I use backspace or remove the whole search criteria to see again my whole array information. I must admit I know how my code is working and what is expected but I do not know how to do it. Any ideas?
React v15.1
I am creating a table with a variable number of rows, depending on the data provided via props. Here is where I am (and it works fine):
getRows = () => {
const rows = [];
for (const col in this.props.tableRows) {
if ({}.hasOwnProperty.call(this.props.tableRows, col)) {
rows.push(React.cloneElement(this.props.tableRows[col], {}));
}
}
return rows;
}
I am working on making the console warnings disappear. This old favorite is appearing Each child in an array or iterator should have a unique "key" prop. Check the render method of 'TableData'.
What is the best way to add a key to cloned elements that I am pushing to an empty array?
OR is there a better way to handle this data on dynamically-generated table rows?
This is for an upload dialog for contact information I am using in many places. It successfully performs as expected, just need to add a key...or make it even better.
#medet-tleukabiluly has the right answer:
keyed_items = items.map((item, key) => React.cloneElement(item, {key}))
as long as each item is an element (not just a string).
It would probably make more sense to use the .map function and render JSX so you can easily assign a key to each table row.
function getRows() {
const {tableRows} = this.props;
return tableRows.map((row, index) =>
<tr key={index}>
// whatever else you wanted to add inside each row
</tr>
);
}
This is mostly just a guess for what you're trying to do - if it doesn't work for you, please post a comment that describes your problem in more detail and I can edit this answer to provide a better solution for you.