Is it good solution to join (interact) Redux with flux in one project like below?
The state (inputText) is in our component (TOdoInput), not in store as it should be in Redux. Is it correct to have local state in Redux?
class TodoInput extends Component {
constructor(props, context) {
super(props, context)
this.state = {
inputText: ''
}
}
handleChange(event) {
this.setState({
inputText: event.target.value
})
}
handleSubmit(event) {
event.preventDefault()
this.props.addTodo(this.state.inputText)
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit.bind(this)}>
<input
type="text"
placeholder="Type in your todo"
value={this.state.inputText}
onChange={this.handleChange.bind(this)}
/>
<input type="submit" value="Submit"/>
</form>
</div>
)
}
Yes it is correct.
Local (component state) vs Global state (reducer) is a matter of concern.
For example take a tabs bar component which displays user informations
A tabs bar should know which tabs is active. No other component cares about so it could be a local component state handled with this.state.
On the other hand the user information of the tab is a global concern. Indeed, a lot of your components app should be interested to display name, age, etc. So this state should be stored in a reducer.
The main role of your TodoInput is to prepare the text to be send to the reducer. So input value is only important during the time the user is typing.
you can format the text
you can ask to a service is there is a typo
...
Once you are sure the text is OK with the concern of you app, you validate it. At this step, the concern of you value changes. It is now a value which could be consumed by other components. So it must be stored in a global store (the redux reducer).
Related
I was doing autocomplete class so I wanted to set the state in each changes of input value.
like:
state = {
value: ""
}
render(){
console.log("called");
return(
<div>
<input type="text" onChange={(e) => this.setState({value: e.target.value})/>
</div>
);
}
So in console I get "called" twice in each changes.
Could you please tell if it is fine or not?
You shouldn't assign the values to the state that way, the recommended way for Class based components is to use
this.setState()
I am new to react and while learning I come across this example of controlled component.
function App() {
let [fName, setFName]=useState('');
return (
<div className="container">
<h1>Hello {fName }</h1>
<input name ='fname' value={fName} onChange={(e)=> setFName(e.target.value)} type="text" placeholder="What's your first name?" />
</div>
);
}
just adding value={fName} makes is controlled . I don't actually understand what does it mean by controlled component and uncontrolled. Can you explain it from beginner prospective.
An uncontrolled component means that you will let the component itself manage the value. It's own internal mechanism will keep track of it.
Now when you add the value property to the input component, you will start to "control" the component yourself. The value you put into that property, will be the value that will be displayed.
You can literally control the value yourself, by just passing it in as is, or by changing the value before passing it in.
Controlled Components
These components have what is called a callback function that is triggered each time we enter something new in the form element.
Triggering the function will typically store or update what we type in the same React component that displays the form element that was used
Most widespread use it with forms
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Unontrolled Components
These components such as <input> typically maintain their own state and update it based on user input.
In other words, they will accept what we type and have the responsibility of remembering it, and in order to retrieve the values they remembered, you have to get it when you need it.
The latter usually happens during form submission. They can be classified under uncontrolled components.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Here, Reactjs documentation provided explanation.
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/stateless component.
An 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.
React form components support both controlled and uncontrolled usage:
// Uncontrolled:
<input type="text" defaultValue="hey" ref={inputRef} />
// Controlled:
<input type="text" value={this.state.value} onChange={onHandleChange} />
We can send data as props from parent component to child component easily but what to do in case of no relationship between two components ?
Please Read my context first so that I can make you understand my problem easily.
In my e commerce react App, when any new user visits my site I want to recommend the user to register. In registration process I keep two steps.
At first I want to take his mobile number from only one input field. when he fills the field and press 'continue' button -
I want to take him another page (component) where from I can take his name, password etc.
Here these two components are independent to each other. When user hits the 'continue' button I am calling a and redirect him to another component.
Now my question is How do I preserve this mobile number in 1st component and send to the 2nd component
[N.B: I don't want the mobile number be visible in the url when calling the 2nd Route]
First Component
export default class FirstComponent extends Component {
render() {
return (
<div>
<input type="text" placeholder="Type Mobile number" />
<Link to={{ pathname: '/signup' }}>
<button>Continue</button>
</Link>
</div>
)
}
}
Second Component
export default class SecondComponent extends Component {
render() {
return (
<div>
<input type="text" placeholder="Type Mobile number" />
</div>
)
}
}
Router
<Route exact path="/signup" render={(props) => {return <SecondComponent />} }/>
You can do it this way:
<Link to={{ pathname: '/signup', state: { number: 3199192910} }}>
<button>Continue</button>
</Link>
And you can access that in your signup component like:
import {withRouter} from 'react-router';
class SecondComponent extends Component {
render() {
// get the number
console.log(this.props.location.state.number)
return (
<div>
<input type="text" placeholder="Type Mobile number" />
</div>
)
}
}
export default withRouter(SecondComponent);
Check out this example, Quotes is what you should be looking at:
On click of button, you can call handleClick function and inside this function you could use push method to send props. This way you would have more control over what representation you want to send your data to other component.
<button onClick={this.handleClick}>continue</button>
handleClick = () => {
this.props.history.push({
pathname: '/signup',
state: { mobile: this.state.mobileNumber }
})
}
Hope that helps!!!
This is where Redux comes into the picture.
Redux is an open-source JavaScript library for managing application state.
So what happens in redux we having something called store which manages the whole state of the application. we dispatch some actions to the stores which calls a function called reducer which mutate the data in the store based on the action that has been dispatched. don't worry if you didn't understand what I said
just watch this 15 min video and you'll completely understand how to use Redux in your application and solve your problem https://www.youtube.com/watch?v=sX3KeP7v7Kg
in order to learn in depth I will recommend you go through the https://redux.js.org/basics/basic-tutorial
now coming back to your problem all you have to do is create a store which saves phone no and when the user clicks on continue button dispatch an action to the reduces to store the phone no and thus your phone no is persisted throughout the application and whenever you want to access the phone just write mapstatetoprops function which is shown in the video to access the data from the store and use it in that component
Hopefully, this will solve your problem
what happens when you don't use redux
of course, you send data as props but what will happen to the props when you refresh the page!!!! the props are lost but when we use redux we can save the data. And you're application works as expected even after refreshed of course they are many other ways to do it
I have a form which is passed a value through props, and submits to an endpoint to update a users information. However, I'm unable to send an edited value of the text input field, as its state needs to be managed and updated when a user changes its value, but having trouble setting/updating the state of the input when the user changes the value, allowing a different value to be posted.
class DisplayNameModal extends React.Component {
constructor (props){
super(props)
this.state = {
displayName: this.props.displayName,
email: this.props.email.split('#')[0]
}
this.updateDisplayName = this.updateDisplayName.bind(this)
}
updateDisplayName () {
const email = this.props.email
const displayName = this.state.displayName
const user = {
email,
displayName
}
superagent
.put('/api/user')
.send({user})
.then(this.closeModal)
}
handleDisplayNameChange = e => this.setState({ displayName: e.target.value })
render (props) {
const {contentStrings} = this.props.config
return (
<div>
{ !this.props.displayNameModalActive &&
<div className='display-name-container' style={{ backgroundImage: `url(${this.props.bgImgUrl})` }}>
<div className='display-name-content'>
<h2 className='heading'>{contentStrings.displayNameModal.heading}</h2>
<p>{contentStrings.displayNameModal.subHeading}</p>
<input type="text"
defaultValue={this.state.displayName}
onChange={this.handleDisplayNameChange}
minLength="3"
maxLength="15"/>
<button
type='submit'
onClick={this.updateDisplayName}
className='btn btn--primary btn--md'>
<span>{contentStrings.displayNameModal.button}</span>
</button>
<p className='cancel'>{contentStrings.displayNameModal.cancel}</p>
</div>
</div>
}
</div>
)
}
}
export default DisplayNameModal
I think you need an onChange on your <input /> to update displayName on component state.
handleDisplayNameChange = e => this.setState({ displayName: e.target.value });
<input type="text"
value={this.state.displayName}
minLength="3"
maxLength="15"
onChange={this.handleDisplayNameChange}
/>
and instead of defaultValue, use value to make it a controlled input
So then in your updateDisplayName, you would use this.state.displayName instead of this.props.displayName. The prop is just being used to set the initial component state value, allowing it to be edited.
onChange event, call a method, and inside it use this.setState to set the changed text to state as you type in Input box.
On submit, use the updated State value to pass it to the API.
In this way, you can maintain updated value in local state.
You are using uncontrolled input element, ie React doesnt know, wats going on with ur input element.
In order, for React to know about it, it hould be made controlled component.
This can be done by connecting it value to the the state of the component,
Check example below.
This means, that at any time, react will know, wat is the value of the input element
Controlled Components
In HTML, form elements such as , , and typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState().
We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Since the value attribute is set on our form element, the displayed value will always be this.state.value, making the React state the source of truth. Since handleChange runs on every keystroke to update the React state, the displayed value will update as the user types.
With a controlled component, every state mutation will have an associated handler function. This makes it straightforward to modify or validate user input. For example, if we wanted to enforce that names are written with all uppercase letters, we could write handleChange as:
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}
I am trying to insert data in database using multiple components in reactjs. In my first component I have a Form like below (there is not Submit button in this component)
render() {
return (
<form>
<input type="text" name="name" placeholder="Name"/>
</form>
);
}
In second component I am calling that component with if else logic.
In third component I have the submit button like below
<Button
positive icon='checkmark'
labelPosition='right'
onClick={this.insertAddress}
content='Save'
/>
My main issue is using state. How can I use state effectively here ? How can I catch the input values of first component in third component to insert in database ?
You create a parent container. The parent container holds the state, all the methods and event handlers. All of those are binding to the parent.
You then pass the methods and parts of the state down to the children. When they children use them, they will be changing the parent. I created a simple sandbox to demonstrate. You don't need to pass the entire state down, just the parts needed by the children.
https://codesandbox.io/s/q335wnjoyj
Use the concept of Container component.
create a container component which will hold the state of all you child components. keep updating all state related to Data in here. and call save functionality from here.
class Parent extends React.Component{
constructor(props){
super(props);
this.state={
name:'',
email:'',
phone:''
}
this.handleFormChanges = this.handleFormChanges.bind(this)
this.handleSubmit = this.handleSubmit.bind(this);
this.reactToSomeChange = this.reactToSomeChange.bind(this)
}
handleFormChanges(ev){
// handle form and set appropriate state
}
handleFormChanges(ev){
// react to change and set state
}
handleSubmit(){
// update your data store db etc.
}
render(){
return(
<MyForm changes={this.handleFormChanges} />
<IfElse changes={this.reactToSomeChange} />
<Button submit={this.handleSubmit} />
)
}
}
// MyFrom component render function
render() {
return (
<form>
<input type="text" name="name" onChanges={this.props.changes} placeholder="Name"/>
</form>
);
// Button component render function
render(){
<button onClick={this.props.submit}>SUBMIT<Button>
}
Child components need not to call apis to save the data. it should be done from a single parent component that shares the same state in the child components.