React js - how to assign result of a function to a state? - javascript

I have a question about react
currently in my app I want to get some data from server, and set default value of input, all of pulling is done in a function, but when I'm trying set state equal to function looks like react is thinking that I'm assigning function to state as a result on every input change state is being updated with function ignoring actual typing, is there a way to get past this?
Here is code for render part of component:
{metaList["properties"] &&
metaList["properties"].map((item, idx) => (
<label key={idx} style={{ display: "block", marginBottom: "20px" }}>
{item.name + ":"}
<div style={{ display: "none" }}>
{this.findMeta()
? (this.state.properties[item.name] = this.findMeta())
: ""}
{this.state.properties[item.name]
? this.state.properties[item.name]
: (this.state.properties[item.name] = "")}
</div>
<input
name={item.name}
placeholder={item.name}
value={this.state.properties[item.name]}
onChange={this.handleInputChangeProperties}
style={{
marginLeft: "20px"
}}
/>
</label>
))
}
this.findMeta is function I'm trying to call, nothing is special in it, function returns one variable as a string to get field filled.

Related

react set value to a textfield

everytime the closeEmail is triggered or called I wanted to assign the email.emailAddress as the value of the textfield.
just really new to react , what is the syntax or way to do this ?
Any idea guys ?
#code snippet
<div style={{ display: "block" }}>
<FormControl sx={{ mt: 2, minWidth: 720 }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<TextField
style={{ width: "95%" }}
onChange={emailOnChange}
label="Email Address"
variant="filled"
name={email.emailAddress}
defaultValue={email.emailAddress}
/>
<DeleteIcon style={{ color: "red" }} onClick={() => deleteEmail(email, prop.id)} />
</div>
#ts
const closeEmail = (email: IEmail) => {
const test = email.emailAddress;
setOpenEmail(false);
return email.emailAddress;
}
Firstly, you have to create the state for the TextField to set the value
you can achieve with the following changes
import at the top:-
import React,{useState} from 'react';
then create state :-
const[emailValue, setEmailValue] = useState('');
on your function call closeEmail()
const closeEmail = (email: IEmail)=>{
count test = email.emailAddress;
//add
console.log("test",test);
setOpenEmail(false);
return email.emailAddress;
}
Add console to check first you are getting the desired value that you want to set to TextField.
if the value you getting is correct then set the state
const closeEmail = (email: IEmail) => {
const test = email.emailAddress;
//add
console.log("test",test);
//add
setEmailValue(test);
setOpenEmail(false);
return email.emailAddress;
}
Adding this setEmailValue(test) will set state,
now you can access by using 'emailValue'
add the following
<TextField
value={emailValue}
style={{ width: "95%" }}
onChange={emailOnChange}
label="Email Address"
variant="filled"
/>
This is how you can set the email.emailAddress value to TextField
Basically, if you want to control the value of your TextInput you should pass value prop to your TextInput.
<TextField
style={{ width: "95%" }}
value={email.emailAddress}
label="Email Address"
variant="filled"
name={email.emailAddress}
defaultValue={email.emailAddress}
onChange={emailOnChange}
/>
You can have controlled or uncontrolled components:
A Controlled Component is one that takes its current value through
props and notifies changes through callbacks like onChange. A parent
component "controls" it by handling the callback and managing its
own state and passing the new values as props to the controlled
component. You could also call this a "dumb component". A
Uncontrolled Component is one that stores its own state internally,
and you query the DOM using a ref to find its current value when you
need it. This is a bit more like traditional HTML.
you need to pass value of textField like this,
<TextField
value={email.emailAddress}
...
/>

text string must be rendered within a text component

I'm getting this error I read some ways to fix it , but nothing worked
<View style={styles.container}>
<StatusBar
backgroundColor="transparent"
translucent
barStyle={theme.dark ? 'light-content' : 'light-content'}
/>
{open ? (
<DateTimePicker
style={{width: '100%', margin: 5}}
mode="date"
value={date}
dateFormat="day month year"
display="calendar"
onChange={handleDate}
/>
) : (
<Button
style={{margin: 5}}
color="#17E5C2"
onPress={() => {
setOpen(true);
}}>
Filtrar por data
</Button>
)}
{Object.values(JSON.parse(route.params.paramKey).message).map(item =>
Object.values(item.createdAt[0]).filter(actualDate =>
actualDate.includes(dateFilter) ? (
<Card mode="outlined" key={uuidv4()}>
<Title>{item?.createdAt[0].value}</Title>
<Button
style={{alignItems: 'flex-start'}}
color="#17E5C2"
icon={
infoVisible
? 'arrow-up-bold-outline'
: 'arrow-down-bold-outline'
}
mode="outlined"
onPress={() => {
handleInfo();
}}>
Ver detalhes
</Button>
{Object.keys(item).map(data => (
<Card.Content
key={uuidv4()}
style={infoVisible ? {display: 'flex'} : {display: 'none'}}
accessible={false}>
<Paragraph style={{fontWeight: 'bold'}}>{data}</Paragraph> // {data} is a string as I checked in console.log
<Paragraph>{item[data][0]?.value}</Paragraph>
</Card.Content>
))}
<Card.Actions>
<Button color={'#17E5C2'}>Edit</Button>
</Card.Actions>
</Card>
) : (
console.log('NO ACTUAL DATA') // When I change console.log to a react child like(<Text>test</Text>) the error appear's instantly
),
),
)}
</View>
The error appear's when I choose a date that has data.
I tried to put console.log besids react child , and when I put it appears to me the data.
So I tought the error could be in my react childs.
I tried to fix my jsx conditional , but not worked , also tried to remove some commas , but also not worked,
and I tried to use <> </> at the top and the end , but also not worked
Complete error message: Error: Text strings must be rendered within a <Text> component.
I tried the entire day so.... it's been dificulty , I want some tips about how to fix it.
One possible problem I can see from your code
Object.values(item.createdAt[0]).filter(actualDate => actualDate.includes(dateFilter) ? <YourComponent> : console.log('NO ACTUAL DATA'))
You're using filter instead of map for a ternary condition.
filter returns true/false value, so you shouldn't use it in this case
If you want to use it, the proper one could be
Object.values(item.createdAt[0]).filter(actualDate => actualDate.includes(dateFilter))
This error comes when you are not wrapping strings within the component or if you are you using some code formatter it sometimes add {" "} outside the components. Check for these scenarios within your components (P.s:- commenting out code component by component might save you some time)

react native display input on real time

I have a Text Input in React Native and I want to display the typed input on real time (two way binding ) in a way that when typing each letter in the input, the text under the input field is automatically updated with the letter typed. I want to achieve this without the use of state but this code doesn't work
export default function App() {
const updateDisplay=(typedLetters)=> {return (<View><Text>typedLetters</Text></View>)}
return(
<TextInput
style={{height: 40,margin:20}}
placeholder="Search"
onChangeText={(text)=>updateDisplay(text)}
/>)
}
First, updateDisplay should be like this:
const updateDisplay = (typedLetters) => {
return (
<View>
// notice argument is in {}
<Text>{typedLetters}</Text>
</View>
);
};
In order to show the text, you have to call the updateDisplay inside the component:
return (
<View>
<TextInput
style={{ height: 40, margin: 20 }}
placeholder="Search"
onChangeText={(text) => updateDisplay(text)}
/>
{/* what parameter you are going to be passing to this function */}
{updateDisplay()}
</View>
The thing is when you defined the updateDisplay, it receives an argument. So somehow you need to extract the input value of TextInput component. That is why we need to use the state.
TextInput is actually a function and you cannot go inside of a function and grab a value. Inside a function, you mutate the state. we use setState because we are not setting the state, we are asking React and it decides when to set it.
export default function App() {
const [text, setText] = useState(null);
const updateDisplay = (typedLetters) => {
return (
<View>
<Text>{typedLetters}</Text>
</View>
);
};
return (
<View>
<TextInput
style={{ height: 40, margin: 20 }}
placeholder="Search"
// now save the input value to state.
onChangeText={(text) => setText(text)}
/>
{/* what parameter you are going to be passing to this function */}
{updateDisplay(text)}
</View>
);
}
It is not possible to do this without state. Using state you provide a hook for the UI to know when to re-render your component. Without it, your UI will not re-render, and you won't see any difference.

If statement within a map dictionary in react redux

I have a dictionary containing objects with cards. I would only like to display each card if the current user value is equal to the stored user value. IE, if the a given user created that card.
<CardDeck>
{this.props.homeTdps.map(function (tdp, key) {
if ({currentUser.username} == {this.props.tdpDetail.created_by.username})
return (
<Card.Link key={key} href={`/tdps/${tdp.id}/`} style={{ minWidth: '20rem', maxWidth: '20rem' }}>
<Card.Body>
<Card.Title>{tdp.part_name}</Card.Title>
<Card.Text>{tdp.description}</Card.Text>
<Button variant="primary">Download</Button>
</Card.Body>
</Card.Link>
);
// }
})}
</CardDeck>
I am having trouble however syntatically with the the third line:
if ({currentUser.username} == {this.props.tdpDetail.created_by.username})
My current error is as follows...
Any solution is appreciated,
Thanks!
EDIT:
I have also tried removing the curly brackets from the 3rd line:
if (currentUser.username == this.props.tdpDetail.created_by.username)
I then get the error "TypeError: Cannot read property 'props' of undefined".
However, when I print the two values within a header like so, they both print just fine (and the users are the same value).
<h3>{currentUser.username}</h3>
<h3>{this.props.tdpDetail.created_by.username}</h3>
remove the curly bracets from your if statement;
use arrow function at map to properly bind this to your component Class:
{this.props.homeTdps.map((tdp, key) => {
if (currentUser.username == this.props.tdpDetail.created_by.username)
return (
<Card.Link key={key} href={`/tdps/${tdp.id}/`} style={{ minWidth: '20rem', maxWidth: '20rem' }}>
<Card.Body>
<Card.Title>{tdp.part_name}</Card.Title>
<Card.Text>{tdp.description}</Card.Text>
<Button variant="primary">Download</Button>
</Card.Body>
</Card.Link>
);
// }
})}

How to pass different event handlers for the same event?

I have a react-native component which is rendering 2 Icons for marking a favorite and writing a comment as shown below:
function RenderDish(props) {
const dish = props.dish;
if (dish != null) {
return (
<Card featuredTitle={dish.name} image={{ uri: baseUrl + dish.image }}>
<Text style={{ margin: 10 }}>
{dish.description}
</Text>
<View style={{ display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center" }}>
<Icon raised reverse name={props.favorite ? 'heart' : 'heart-o'} type='font-awesome' color='#f50'
onPress={() => props.favorite ? console.log('Aleady Favorite') : props.onFavorite()} />
<Icon raised reverse name='pencil' type='font-awesome' color='#3b5998'
onPress={() => props.onComment()} />
</View>
</Card>
);
}
else {
return (<View></View>);
}}
I am calling this functional component from the outer component as shown below:
<RenderDish dish={this.props.dishes.dishes[+dishId]}
favorite={this.props.favorites.some(el => el === dishId)}
onFavorite={() => this.markFavorite(dishId)}
onComment={() => this.toggleModal()} />
I have already implemented the toggleModal() and the markFavorite() methods and everything is working as expected but my question is: Is there any other way of passing 2 or more different event handlers through a single prop ? For eg. Is there any way to say something like: <RenderDish dish={xyz} onPress={()=> handler1 AND handler2}. Or is there any elegant alternative to what I have done(if I had 5 buttons I would need 5 props :( ) ?
You can have your handlers in a single function and call the function in onPress.
or just
onPress={()=> {handler1, handler2}}
Try something like below. Pass the handler methods as an object in a props.
function Button(props) {
return (
<div>
<button type="button" onClick={props.onPress.handler1} >Handler1</button>
<button type="button" onClick={props.onPress.handler2} >Handler2</button>
</div>
);
}
class Home extends Component {
handler1() {
console.log('handler 1');
}
handler2() {
console.log('handler 2');
}
render() {
return (
<div>
<Button onPress={{ handler1: this.handler1, handler2: this.handler2 }} />
</div>
)
}
}
The way that you’ve done it is probably the most common way and perfectly acceptable.
It’s not generally a problem if there are only a few handlers (and they aren’t being passed deeply).
You could bundle them into an object and single prop, but I don’t typically see it done that way and I don’t think there’s a strong benefit.
You can also pass in multiple props as a single spread object without having to bundle them into a single prop.
If you start getting a more handlers than you’re comfortable with, then that would probably be a good time to look at how you’re handling your state management. You may be better off with a reducer and dispatching actions at that point.
Update
A few other notes about your code:
You can destructure props for easier use.
You do not need a separate closing tag for View if there is no content.
You do not have to make new arrow functions for event handlers if all you are doing is calling another arrow function. You can just set it to the first arrow function.
Consider a ternary to allow an implicit return.
function RenderDish({dish, favorite, onFavorite, onComment}) =>
dish
? <Card featuredTitle={dish.name} image={{ uri: baseUrl + dish.image }}>
<Text style={{ margin: 10 }}>
{dish.description}
</Text>
<View style={{ display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center" }}>
<Icon raised reverse name={favorite ? 'heart' : 'heart-o'} type='font-awesome' color='#f50'
onPress={() => favorite ? console.log('Aleady Favorite') : onFavorite()} />
<Icon raised reverse name='pencil' type='font-awesome' color='#3b5998'
onPress={onComment} />
</View>
</Card>
: <View/>
I would focus more on these items, rather than bundling those two functions.

Categories

Resources