Functional Search Bar in TypeScript - javascript

I have created a Material UI search bar front-end but for now I am unable to type anything into it. How could I fix this?
export default class userSearchPage extends Component <{}, { searchItem: string}>{
constructor(props: Readonly<{}>) {
super(props);
this.state = {
searchItem: 'ha'
};
}
render() {
return (
<div>
<PermanentDrawerLeft></PermanentDrawerLeft>
<div className='main-content'>
{/* <Typography>{this.state.searchItem}</Typography> */}
<SearchBar
onChange={e => {
this.setState({searchItem: e.target.value})
}}
onRequestSearch={() => console.log('onRequestSearch')}
style={{
margin: '0 auto',
maxWidth: 800
}}
/>
</div>
</div>
);
}
}
The onChange method doesn't work and gives an error.
I feel that this method in general is not the ideal way. How else could I make the search bar functional in Typescript so it could read and store what the user types in?

Try this one
<form onSubmit={props.onRequestChange}>
<input id="searchbartext" onChange={props.onChange} />
</form>

Related

'State' is not defined and 'handleToggle' is not defined no-undef

Line 11:5: 'state' is not defined no-undef
Line 15:5: 'handleToggle' is not defined no-undef
I don't understand why it shows me these errors, please help me resolve this, I would also appreciate an explanation
const Footer = () => {
state = {
langContent: false
}
handleToggle = (e) => {
e.preventDefault();
this.setState({
langContent: !this.state.langContent
})
}
return (
<FooterContainer>
<span style={{ marginLeft: '15%', fontSize: '1.125rem' }}>
Questions?
<Link> Call 1-877-742-1335</Link>
</span>
{/* Language Button */}
<div className= "lang-btn" onClick={this.handleToggle}>
<Icon icon={iosWorld} size={20}/>
English
<Icon icon={arrowSortedDown} />
</div>
{/* Toggle Language Content */}
{this.state.langContent && (
<div className="lang-toggle">
<ul>
<li>English</li>
</ul>
<ul>
<li>Hindi</li>
</ul>
</div>
)}
<span style={{ marginLeft: '15%', fontSize: '0.9rem'}}>
Netflix India
</span>
</FooterContainer>
)
}
I think you are confusing the syntax for using state in functional components with the syntax for using states in class components.
To use state in functional components, use it like this: (also you forgot to declare const before the function handleToggle, here you are declaring a function local variable thus const is needed. You are confusing it with declaring a method in a class)
const Footer = () => {
const [state, setState] = useState({ langContent: false })
const handleToggle = (e: { preventDefault: () => void; }) => {
e.preventDefault();
setState({
langContent: state.langContent
})
}
return (
<FooterContainer>
<span style={{ marginLeft: '15%', fontSize: '1.125rem' }}>
Questions?
<Link> Call 1-877-742-1335</Link>
</span>
{/* Language Button */}
<div className= "lang-btn" onClick={this.handleToggle}>
<Icon icon={iosWorld} size={20}/>
English
<Icon icon={arrowSortedDown} />
</div>
{/* Toggle Language Content */}
{state.langContent && (
<div className="lang-toggle">
<ul>
<li>English</li>
</ul>
<ul>
<li>Hindi</li>
</ul>
</div>
)}
<span style={{ marginLeft: '15%', fontSize: '0.9rem'}}>
Netflix India
</span>
</FooterContainer>
)}
If you want to use functional component style, read more about it here: React docs-Using the state hook
The component has been created as a functional component, which does not have state, to fix this issue you can use the useState hook.
const Footer = () => {
const [langContent, setLangContent] = useState(false)
const handleToggle = (e) => {
e.preventDefault();
setLangContent(!langContent);
}
return (
... // Use existing Code
)
}
If you want to continue to using class based components then you should use a class that extends React.Component
class Footer extends React.Component {
constructor(props) {
super(props);
this.state = {
langContent: false
};
}
render() {
... //Use existing Code
}
Additional Reading:
React Docs for hooks-state

React Conditional Rendering of Component Inside Function Not Working

I am using Codesandbox to work on learning React. I am trying to conditionally render a functional React component inside of a function (inside of a class based component), that fires when a button is clicked.
Here is the link to the Codesandbox: https://codesandbox.io/embed/laughing-butterfly-mtjrq?fontsize=14&hidenavigation=1&theme=dark
The issue I have is that, without importing and rendering the Error and Meals in App.js, I never can get either component to render from the Booking component. In the function here:
if (!this.state.name) {
return (
<div>
<Error />
</div>
);
}
else {
return <Meals name={this.state.name} date={this.state.date} />;
}
}
I should be rendering Error, which should then show on the screen on click if no name is inputted but nothing happens and I am stumped.
Is there anything obvious that would be preventing me from seeing the Error component from loading on the click?
Thank you in advance!
Everything that is displayed on the screen comes from render method. You cann't return JSX from any function like that. You can do something like this:
class Bookings extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
date: "",
display: false
};
}
guestInfoHandler = event => {
console.log(this.state, "what is the state");
this.setState({ name: event.target.value });
};
dateInfoHandler = event => {
this.setState({ date: event.target.value });
};
showMeals = () => {
this.setState({ display: true });
};
render() {
return (
<>
<div style={{ display: "inline-block" }}>
<form
className="theForm"
style={{
height: "50px",
width: "100px",
borderColor: "black",
borderWidth: "1px"
}}
>
<label className="theLabel">
Name:
<input
className="theInput"
type="text"
placeholder="guest name here"
onChange={this.guestInfoHandler}
value={this.state.value}
/>
</label>
</form>
<form>
<label>
Date:
<input
type="text"
placeholder="date here"
onChange={this.dateInfoHandler}
value={this.state.value}
/>
</label>
</form>
<button onClick={() => this.showMeals()}>Click</button>
</div>
{ display && name ? (
<Meals name={name} date={name} />
) : (
<Error />
)}
</>
);
}
}
export default Bookings;
Hope this works for you.
render() {
const name = this.state.name;
return (
<div>
{name ? (
<Meals name={name} date={name} />
) : (
<Error />
)}
</div>
);
}
nb:use render method in class component only.
there is various types conditional rendering mentioned in
https://reactjs.org/docs/conditional-rendering.html#

How to pass state from child component to parent in React.JS?

I have a form that has 10+ input fields that update the state of the class. To make things look cleaner I moved all input fields with labels into a separate component so I could re-use it for each input instead. This component takes 2 parameters and serves as a child in my main class.
child component:
const Input = ({ name, placeholder }) => {
return (
<div className="wrapper">
<Row className="at_centre">
<Col sm="2" style={{ marginTop: "0.5%" }}><Form.Label>{ name }</Form.Label></Col>
<Col sm="5"><Form.Control placeholder={ placeholder }/></Col>
</Row>
</div>
)
}
parent:
state = { name: '', description: '' }
handleSubmit = (e) => {
e.preventDefault()
console.log(this.state);
}
render(){
return(
<Form style={{ marginBottom: "5%", padding: 10 }} onSubmit={ this.handleSubmit } >
<Input name="Name: " placeholder="How is it called?" onChange={ (event) => this.setState({name: event.target.value}) }/>
<Input name="Description: " placeholder="Please describe how does it look like?" onChange={ (event) => this.setState({description: event.target.value}) }/>
<Button variant="outline-success" size="lg" type="submit" >SUBMIT</Button>
</Form>
)
}
After I did that I can't find the way how to update the state from my child components when the text is changed. All my attempts to do so either crashed the website or did nothing. I am still new to React.js so any feedback is appreciated.
Pass onChange event to your child component and wire it with Form.Control control.
Your Input component will be,
const Input = ({ name, placeholder, onChange }) => {
return (
<div className="wrapper">
<Row className="at_centre">
<Col sm="2" style={{ marginTop: "0.5%" }}>
<Form.Label>{name}</Form.Label>
</Col>
<Col sm="5">
<Form.Control onChange={onChange} placeholder={placeholder} />
</Col>
</Row>
</div>
);
};
And your Parent component is,
class Parent extends React.Component {
state = { name: "", description: "" };
handleSubmit = e => {
e.preventDefault();
console.log(this.state);
};
render() {
return (
<Form
style={{ marginBottom: "5%", padding: 10 }}
onSubmit={this.handleSubmit}
>
<Input
name="Name: "
placeholder="How is it called?"
onChange={event => this.setState({ name: event.target.value })}
/>
<Input
name="Description: "
placeholder="Please describe how does it look like?"
onChange={event => this.setState({ description: event.target.value })}
/>
<Button variant="outline-success" size="lg" type="submit">
SUBMIT
</Button>
</Form>
);
}
}
Working Codesandbox here.
In React, properties flow from the parent component to the child component, so you cannot directly "pass" the state from the child to the parent.
What you can do however is to have the parent pass a callback function to the child that will be called to update the parent's state.
Here is an example:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
};
}
updateName(name) {
if (name === this.state.name) return;
this.setState({ name });
}
render() {
return (
<div>
<p>The name is {this.state.name}</p>
<ChildComponent handleNameUpdate={name => this.updateName(name)} />
</div>
);
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
};
}
handleInputChange(e) {
this.setState({ name: e.target.value });
this.props.handleNameUpdate(e.target.value)
}
render() {
return <input type="text" value={this.state.name} onChange={e => this.handleInputChange(e)} />;
}
}
You have to build what is known as a controlled component.
const Input = ({ label, name, onChange, placeholder }) => (
<div className="wrapper">
<Row className="at_centre">
<Col sm="2" style={{ marginTop: "0.5%" }}>
<Form.Label>{ label }</Form.Label></Col>
<Col sm="5">
<Form.Control name={ name }
value={ value }
placeholder={ placeholder }
onChange={ onChange }
/>
</Col>
</Row>
</div>
)
And in your parent,
state = { name: '', description: '' }
handleChange = ({ target: { name, value } }) => this.setState({ [name]: value })
render() {
const { name, description } = this.state
<Form style={{ marginBottom: "5%", padding: 10 }} onSubmit={ this.handleSubmit } >
<Input label="Name: " name="name" value={name} onChange={handleChange}/>
<Input label="Description: " description="description" value={description} onChange={handleChange}/>
<Button variant="outline-success" size="lg" type="submit" >SUBMIT</Button>
</Form>
}
Advice
Try to avoid manufacturing lambda methods inside the render function as much as possible and have a class property as a lambda method so that lambdas do not need to be manufactured on every render cycle.

React - Fill array in state with input value

I have an empty link array and three input fields on my page.
I want to get the values of all three input fields in one array in my state variable link[] so that I can send a link array to my DB.
Like you see I am using semantic ui but for the input fields there is just the onChange function I can use
How can I do that?
export default class Dashboard extends Component {
constructor() {
super();
this.state = {
link : []
};
render() {
return (
<Grid style={{ height: "100%" }}>
<Grid.Column width={6} className='dashboardCard'>
<Card fluid>
<Card.Content >
<Card.Header>Allgemeine Künstler-Daten</Card.Header>
<Card.Description>
"Strange Fruit" is a song performed most famously by Billie
Holiday, who first sang and recorded it in 1939.
</Card.Description>
</Card.Content>
<Card.Content extra textAlign="center">
<Form onSubmit={this.handleSubmit} >
<Input
fluid
label="Social Link 1"
placeholder="www.twitter.com/artist"
style={{ margin: "1rem" }}
width={6}
name="link"
value={this.state.link}
onChange={this.handleInputChange}
/>
<Input
fluid
label="Social Link 2"
placeholder="www.soundcloud.com/artist"
style={{ margin: "1rem" }}
width={6}
name="link"
value={this.state.link}
onChange={this.handleInputChange}
/>
<Input
fluid
label="Social Link 3"
placeholder="www.facebook.com/artist"
style={{ margin: "1rem" }}
width={6}
name="link"
value={this.state.link}
onChange={this.handleInputChange}
/>
<Dropdown
<Form.Button positive
value="Submit">Save</Form.Button>
</Form>
</Card.Content>
</Card>
</Grid.Column>
<Grid.Column columns={5} />
</Grid>
);
}
I would recommend not storing the links in an array but as separate values with distinct keys in your component's state. That way you'll know which link to update if the user changes something. Just have keys in the state that correspond to inputs that are rendered, using the <input> name attribute. It's also convenient to wrap all of the data from the form in a formOptions key in the state in case you have other state data.
You can do something like this:
constructor() {
super();
this.state = {
formOptions: {
link1: '',
link2: '',
link3: ''
}
};
}
handleInputChange = event => {
const { name, value } = event.target;
const { formOptions } = this.state;
formOptions[name] = value;
this.setState({ formOptions });
}
Then just give your inputs the name attributes link1, link2, and link3.
Then in your handleSubmit method, you can convert the separate links into a single array if that's how you need to send them.
Note that the method handleInputChange needs to be written as an attribute assigned to an arrow function for binding this to the component so that the state can be accessed. Alternatively you can just define handleInputChange normally and then in each input's onChange put this.handleInputChange.bind(this), but I find the first way a bit cleaner.

React - TypeError: _this.setState is not a function

I am playing with React and trying to save the text that user type to the input to the state. I have added to the textarea an onChange attribute for setting the state.
However, when I start typing, I see error in the console stating TypeError: _this.setState is not a function.
I've tried different ways of trying to fix it, but still don't have it.
const NewItemForm = props => (
<Form onSubmit={props.send_form}>
<Form.Group>
<TextArea
placeholder='Name your first item here'
name='item_msg'
onChange={e => this.setState({ item_msg: e.target.value })} />
<Form.Button primary content='Create Item' />
</Form.Group>
</Form>
)
class App extends Component {
constructor () {
super();
this.state = {
item_msg: ''
}
}
handleSubmit(e){
e.preventDefault();
console.log(this.state.item_msg);
}
render() {
return (
<div className="App">
<MainHeaderr />
<Container>
<NewItemForm send_form={this.handleSubmit.bind(this)} />
</Container>
</div>
);
}
}
export default App;
Functional components do not have lifecycle methods and... state :)
const NewItemForm = props => (
<Form onSubmit={props.send_form}>
<Form.Group>
<TextArea
placeholder='Name your first item here'
name='item_msg'
onChange={e => this.setState({ item_msg: e.target.value })} />
<Form.Button primary content='Create Item' />
</Form.Group>
</Form>
)
This won't work:
onChange={e => this.setState({ item_msg: e.target.value })} />
What you need is to pass callback:
const NewItemForm = props => (
<Form onSubmit={props.send_form}>
<Form.Group>
<TextArea
placeholder='Name your first item here'
name='item_msg'
onChange={props.onInputChange} />
<Form.Button primary content='Create Item' />
</Form.Group>
</Form>
)
class App extends Component {
constructor () {
super();
this.state = {
item_msg: ''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleSubmit(e){
e.preventDefault();
console.log(this.state.item_msg);
}
handleInputChange(e) {
this.setState({ item_msg: e.target.value })
}
render() {
return (
<div className="App">
<MainHeaderr />
<Container>
<NewItemForm send_form={this.handleSubmit} onInputChange={this.handleInputChange} />
</Container>
</div>
);
}
}
I get where you are coming from, but NewItemForm will get transpiled to React Element so this will reference that Element, not the App component.
React without JSX
Functional components are stateless so you can't call setState within them. You can pass a callback from your parent component that sets state in the parent component as follows:
handleChange = e => this.setState({ item_msg: e.target.value });
<NewItemForm onChange={this.handleChange} />
And then in your NewItemForm component:
<TextArea
placeholder='Name your first item here'
name='item_msg'
onChange={props.onChange}
/>
NewItemForm is function component and function comopent does not have lifecycle method use class component.
You need to either use arrow function or bind the function in constructor like below
constructor(props) {
super(props);
this.state = { date: new Date() };
this.tick = this.tick.bind(this);
}
setInterval(()=>this.tick, 1000);
or Use arrow function
setInterval(()=>this.setState({
date: new Date(),
}), 1000);

Categories

Resources