on the homepage of React, there's the last example (A Component Using External Plugins) with a textarea:
<textarea
id="markdown-content"
onChange={this.handleChange}
defaultValue={this.state.value}
/>
As I type, the textarea gets updated.
Now, I tried to change defaultValue with value:
<textarea
id="markdown-content"
onChange={this.handleChange}
value={this.state.value}
/>
And the outcome is the same (as with defaultValue, i.e. as I type, the textarea gets updated visually with the updated text).
So, what is the real difference between the two?
I think a good example for this is if you use a hard coded string
using defaultValue prop:
function App(){
return(
<textarea
defaultValue="foo" // only by default foo
/>
);
}
ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
using value prop
function App(){
return(
<textarea
value="foo" // will forever be foo
/>
);
}
ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
So while the snippet below this paragraph might look like it is the same as using value prop because of onChange potentially updating the state value (therefore it looks like it is updating defaultValue prop) - it is not. It is still an uncontrolled component and will update its value directly from the user input. It is simply initialized with the default value of whatever this.state.value is when it is initially rendered.
<textarea
id="markdown-content"
onChange={this.handleChange}
defaultValue={this.state.value}
/>
As long as you change the value that is used in value there won't be any difference. If you won't update the variable and have set a textareas value you can't change the value of the textarea by typing. By using a defaultValue you don't have to update any variable.
see demo image here
You can edit the input value without onchange event handler when you use default value with the input tag.
If you use value with input tag you need to use onchange event handler to make changes to input value.
Related
I know how to pass data from a parent component to a livewire component, but how to do it, if the value is dynamic and generated by JavaScript?
<x-my-layout>
<livewire:my-component id="test" foo="this value should be passed" />
#push('scripts')
<script>
const livewireComponent = document.getElementById('test'); // <-- this is not working
livewireComponent.setAttribute('foo', 'bar'); // <-- In consequence this is not working
</script>
#endpush
</x-my-layout>
Please don't answer, that I just can use <livewire:my-component foo="bar" />, because I need to pass a value that is generated on client side like an text input.
Blade-components are rendered server-side, and thus you cannot set that property via Javascript like that. You would have to emit an event instead. Here are some examples on how you can do that. All of these following examples that are event-based, which means that you would have to listen for it within your component by adding
protected $listeners = ['setFooProperty'];
public function setFooProperty($value)
{
$this->foo = $value;
}
Using Alpine.js with x-init
<x-my-layout>
<div x-data x-init="Livewire.emit('setFooProperty', 'bar')">
<livewire:my-component id="test" foo="this value should be passed" />
</div>
</x-my-layout>
Using a global emit event with JavaScript
<x-my-layout>
<div x-data x-init="$wire.emit('setFooProperty', 'bar')">
<livewire:my-component id="test" foo="this value should be passed" />
</div>
#push('scripts')
<script>
Livewire.emit('setFooProperty', 'bar');
// or
Livewire.emitTo('my-component', 'setFooProperty', 'bar');
</script>
#endpush
</x-my-layout>
As I understand you can not change the props value directly in the child component.
But I find out that this will work, I want to know the reason behind it.
For reference: I am using vue3+vite
For example:
<template>
<input v-model="price"/>
</template>
<script lang="ts" setup>
defineProps({
price : Number
});
</script>
this can change the props value based on the input. with no warning or error
but if I write this way
<template>
<input v-model="props.price"/>
</template>
<script lang="ts" setup>
const props = defineProps({
price : Number
});
</script>
there will be a warning in the console.
notice I didn't write any computed to handle the change of the props.
Is it a bad practice?
Both should issue warning. The reasoning is that the parent will not usualy be aware of the change unless it is mutated there. It also allows the parent to validate the change. The idea is that only the owner of the data should modify it.
So emit an event instead. The conventional way to write the code is.
<input :value="price" #input='$emit("input", $event)'/>
// or
<input :value="price" #update:value='$emit("update:value", $event)'/>
// or
<input :value="price" #input='$emit("update:value", $event)'/>
You can access both because Vue automatically exposes both the props object itself and all the props' properties into the template.
As you can see the code from my Visual Studio Code, it won't let me type within the text input if I render the code
The onChange event on line 36 invokes (updateInput) function.
Which doesn't exist or declared inside the component, if you sent it as a prop use :
this.props.updateInput(_params_)
Otherwise declare the function inside the component in order to make the event work properly.
That's because <input /> has constant value, so you need to change value to defaultValue.
<input
type="text"
placeholder="Insert text"
defaultValue={this.state.newItem}
onChange={() => {}}
/>
I'm trying to figure out why a call to this.setState isn't updating state.
I have the following lines method:
changeState(state, value){
this.setState({state:value}, ()=>console.log(this.state));
}
There are a few function using this, but one is a file upload component. Its a simple component that either renders a file input OR it renders an iframe, disabled input, and button. When the button is clicked I want to change the state in the parent component which then rerenders the file component and shows a file picker.
The call to this.setState seems to work ok, but when I console log state after it runs or if I stop execution before the next render takes place state is unaffected. My file upload component has a method like this:
renderField(field){
if(this.props.hasOwnProperty('file') && this.props.file){
return(
<div>
<iframe src={this.props.file} frameborder="0"> </iframe>
<input
disabled
placeholder={this.props.file}
name={field.name}
type='text'
/>
<span onClick={()=>this.props.changeFile(this.props.file_type, null)}>× Remove</span>
</div>
)
}else{
return(
<input
{...field}
type={field.type}
name={field.name}
onChange={(event) =>{
field.input.onChange(field.input.value = event.target.files[0])}
}
/>
)
}
}
when I call the method I get this output:
however after console logging my state is anything but changed:
You don't want to set the state property in your state, but the property name that state contains.
You can use a computed property name for this.
changeState(state, value) {
this.setState({ [state]: value }, () => console.log(this.state));
}
I'm creating my first application with ReactJS and I found this warning when I run my code :
Warning: Failed form propType: You provided a checked prop to a form
field without an onChange handler. This will render a read-only
field. If the field should be mutable use defaultChecked. Otherwise,
set either onChange or readOnly. Check the render method of
Login.
Can someone tell me how I fix it please ?
React has 2 ways of working with form controls - Controlled Components and Uncontrolled Components
You get this warning when you don't supply the element neither the attributes needed for controlled nor those needed for an uncontrolled component:
Warning: Failed form propType: You provided a checked prop to a form
field without an onChange handler. This will render a read-only field.
If the field should be mutable use defaultChecked. Otherwise, set
either onChange or readOnly. Check the render method of Login.
Controlled Components
Attributes needed:
value - <input> (not checkbox or radio), <select>, <textbox> or checked for (checkbox or radio).
onChange
React handles the condition of the element by updating the value or checked attribute (depending on the element) from the props or the state. We need to notify react when we make a change, like inserting data, or checking the box, so react can update the element's condition when it rerenders the component. To do so, we must include an onChange handler, in which we will update the state or notify the component's parent, so it will update the props.
<input
type="checkbox"
checked={ this.props.checked }
onChange={ this.checkboxHandler }
/>
const { render } = ReactDOM;
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
checked: true
};
this.checkboxHandler = this.checkboxHandler.bind(this);
}
checkboxHandler(e) {
this.setState({
checked: e.target.checked
});
}
render() {
return (
<input
type="checkbox"
checked={ this.state.checked }
onChange={ this.checkboxHandler }
/>
);
}
}
render(
<Demo />,
document.getElementById('demo')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js"></script>
<h1>The Checkbox</h1>
<div id="demo"></div>
Uncontrolled Components
Attributes needed:
defaultValue - <input> (not checkbox or radio), <select>, <textbox> or defaultChecked for (checkbox or radio).
React sets the initial value using defaultValue or defaultChecked, and the update of the element's state is controlled by the user, usually via the DOM using refs.
<input
type="checkbox"
defaultChecked={ this.props.checked }
/>
The defaultChecked may not be updated if the component is re-rendered in future so use this approach with caution.
You may be better off just using a blank function to remove the warning. Especially if you want to handle click on the whole div which includes the checkbox and the associated text.
<div onClick={this.handleClick}>
<input type="checkbox" checked={this.props.checked} onChange={()=>{}}/>
{this.props.text}
</div>
You need to add defaultChecked attribute to your checkbox:
<div>
<input type='checkbox' defaultChecked />
</div>
For those that prefer a Functional Component instead of a Class Component this Controlled Component approach is simple and easy to implement. If you don't know what a Controlled Component is then please refer to #Ori Drori's well explained answer in this thread.
import {useState} from "react";
export default function YourComponentName(){
const [checked, setChecked] = useState(true);
return (
<>
<input
type="checkbox"
checked={checked}
onChange={() => setChecked(!checked)}
/>
</>
);
};
If your confronting with this warning, You can add "readOnly" to your input. like this code:
<div>
<input type='checkbox' checked={ props.checkBoxChecked } readOnly />
</div>
Or You can add an onChange event like an empty arrow function or what kind of function you care about to your input. like this:
<div>
<input type='checkbox' checked={ props.checkBoxChecked } onChange={() => {}} />
</div>
Also you must care about the value property, too.
This solution fixed my issue with the same warning, hope to be useful.