How to assign value to a prop NOT inside onChange in ReacJS? - javascript

I have a multi-step Form components and I need to update a state that been sent from a different component.
in the first component I have states:
export class BookForm extends Component {
constructor(){
super()
this.state = {
service: '',
price: ''
Now I have this method:
handleChange = input => event => {
this.setState({
[input]: event.target.value
});
}
I pass this method with the other props to a diffrent component and whenever "onChange" happends I call it with the name of the prop inside like this:
onChange={this.props.handleChange("service")}
That way the onChange event is assiging to the prop.
I have a problem because I have a value that is coming back from an API and I need to assign it to a prop.
I'm having trouble to assign the value inside the prop from the second component without 'onChange'.
Is there a method I can pass to the component that I can use? The function I showed here works with onChange.
Thanks a lot!
Edit:
This is the part from the child component:
<select
class="form-drp-btn"
onChange={this.props.handleChange("service")}
onInput={(e) => {this.setPrice(e)}}
>
the steps are like this:
with "onChange" I get the service that been chosen. with "onInput" I get the price that coming back from the API and belong to the certain service.
Now, I want to assign this value to the "price" state that came from the father component.

Related

React.js callback function as prop makes a parent component re-render three times when the child component changes

In the beginning, I have a component called Search which has two child components SearchBar, and FilterBar. I created a function called onSearchSubmit, and onFilterSubmit which I pass them as callback prop functions to SearchBar and FilterBar respectively.
so it looks like that in the Search.js
const onFilterSubmit = (e) => {
e.preventDefault()
const filteredStacks = filterInput.map((stack) => { return stack.value }) //Extract the values field only
setCompanies([])
fetchData(fetchFilterData, filteredStacks) //API Call
setFilterInput([])
}
//use the API providing it the search input, and
//setCompanies hook to update list of companies
//I did this approach to avoid re-rendering
//whenever the user types in the input field
const onSearchSubmit = (e) => {
e.preventDefault()
setCompanies([])
fetchData(fetchSearchData, inputRef.current.value) //API Call
inputRef.current.value = ""; //useRef hook also passed as prop to the searchBar to access the input value in the input field.
}
and also the component is returned as follows
...
<SearchBar inputRef={inputRef} onSubmit={onSearchSubmit} />
<FilterBar filterInput={filterInput} onChange={setFilterInput} onSubmit={onFilterSubmit}/>
...
Now, inside the SearchBar I wrote a useEffect hook to re-render the component when the onSearchSubmit function changes or gets called (I guess?)
const SearchBar = ({inputRef,onSubmit}) => {
useEffect(()=>{
console.log('search now')
},[onSubmit])
return (
<Form
className="search-form"
onSubmit={onSubmit}
>
....
Then I tried to run it now, and found that search now is logged three times, which is weird actually I don't understand how.
In addition it will also log for 3 times when I search for a keyword. And logs one time if I applied a filter
I understand that a child component which is the SearchBar here will re-render because the component changed when onSubmit was called, but I don't understand why the parent component re-rendered since it I believe created the function once again three times causing the change in the SearchBar component.
Yet when I wrapped the function in useCallback hook, it only logged search now just once, and didn't log when I submitted a search nor when I applied a filter. Which is understandable since the callback prop function onSearchSubmit is now memoed.
So my question is why is the parent component is affected and re-creates the onSearchSubmit three times although the child component is one who is changed? Is there anything I am missing?

How to pass the Key ID back from child component to the parent component-FCC Drum Machine

Here is the element of array of object :
{
keycode:"X"
id: 'Kick',
url: ''
},
I have a stateful class component (App) which generates audio elements mapping the array and using the function PlayAudio.
This will generate buttons associated with audio element which are rendered in the parent component which will play sound on pressing the button. Now, each objects has distinct sound , key and id associated to them.
I want to have a display element in the parent element to display the unique id associated to the button pressed. For that whenever a button is pressed that corresponding id is to be passed to parent component.
How to send the id of the pressed key from the child component to the parent component?
Here is the full code on codepen
One way of solving this is to put the key id inside a state in the parent component and then pass the setId function to the child.
For example in the parent component:
const [id, setId] = useState('initialValue')
Then pass setId as a prop to the child.
If you prefer to use a class component this is how you declare:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
id: 'initialValue'
};
}
...
}
In a class component the property setState is used to change the state:
E.g.: this.setState({ id: 'newValue' })
You can find more info in the react documentation: https://reactjs.org/docs/hooks-state.html

What is the best approach in React Application for the case without using Redux?

I want to submit data via an api on a click of button in the parent Component, on collecting data from multiple sub components in different hierarchy.
I have a discussion on the case with one of my colleague and he suggest me to have a method in a parent comp. and share that (as a handler) to child(s) in prop and then to further to its child(s), keeping child comp. as stateless comp. Such that when user inputs the data it will store into a state variable (in parent comp.) via that handler method. For e.g:
class Parent extends Component {
constructor(props){
this.state.data = {}
}
updateHndler(key, value){
this.setState({
data : {...this.setState.data, key: value}
})
}
}
const ChildA = props => {
onComplete(e){
this.props.updateHndler('text', e.target.value)
}
return (<div>
...
..
<input .. onChange={()=>{onComplete(e)}}
</div>)
}
As each sub-component setting the value in parent state variable for each value it is getting update and its render() method keeps trigger, considering the rendering cost for all the sub-components on each change is the above approach is even good enough?
Thanks

Handle child component update (controlled vs uncontrolled)

There is a Parent component which container a Child component.
Parent supposed to load the data (e.g. using AJAX) and update the Child inputs.
Child supposed to listen for the changes to its inputs and update them as well.
Setting Child props from Parent sets inputs values:
<input value={this.props.someVal}
But this makes it unable to self-update the child, since in order to self-update its inputs it has to use:
<input value={this.state.someVal}
Does this mean, Child has to listen for input change and triggers Parents handler-function that will sets its props?
I thought that setting components props - auto-updates corresponding state (triggering re-render) and that using <input value={this.state.someVal} should cover both cases.
There really isn't any connection between props and state. These are two different mechanisms: state is internal to the component and used for keeping encapsulated data. Props are sent by an enclosing object, as you've done.
There are several ways to go about this, but the general consensus is that having state in one place and passing it down the component tree leads to less messy code and bugs. That means your statement is correct - you'll have to pass update functions to the child component from the parent, so that when invoked it will re-render the child with new props.
I have found the way to do it. Smth like (TypeScript syntax):
componentWillReceiveProps(props: Props) {
this.setState({
data: props.data
})
}
This will allow to update the child both from the parent and child itself. Not sure whether this is a right approach, but it kinda works.
Parent component will make the ajax call and set its own state, the state values will be passed as props, which will update the child always.
class parent extends React.Component {
state = {
value: null
}
componentWillMount() {
this.makeApiCall()
}
makeApiCall = () => {
fetch("api_ulr")
.then(() => {
this.setState({
value: newValue,
})
})
}
render() {
return ( < Child value = {
this.state.value
} > < /Child>)
}
}
now child will update whenver a new data comes.

How do I do a simple onClick to change a child component's classname with React Redux?

I have React Redux working to change my child component's classname, but I do it via
//Subscribe with our function that sets our state
this.props.store.subscribe( this.onSelectChange );
(where the onSelectChange is a function in my component that changes a property on its state.
According to the redux docs, I should instead be using "a view binding library" like ReactRedux's connect method. But every tutorial is incredibly complex. They're hard to understand and appear to be about 5 times more code than what I need to use right now. Using Redux directly, I have about 6 lines of total code.
How can i simply use the "proper" way to make my child component change its classname?
If really all you need is to update a classname on click, React is perfectly capable of doing this without involving the Redux store.
The whole idea with React is that each component has some state object, and a render function to turn the state into markup. If you want to change your view, you should change the state and let React call render again. Take the following example which toggles the classname of a button (not tested):
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
highlighted: false
}
this.buttonClicked = this.buttonClicked.bind(this);
}
buttonClicked() {
var highlighted = !this.state.highlighted
this.setState({
highlighted: highlighted
})
}
render(){
var classname = this.state.highlighted ? "highlighted-btn" : "normal-btn"
return (
<button onClick={this.buttonClicked} className={classname} />
)
}
}
We trigger render by calling setState, in which we use the state to determine the classname for the button.
solution 1
well, if you change className because you want different style.
I will suggest you can use setState in its childComponent instead.
here is for your reference
solution 2
on the other hand, if you want to use Redux to achieve that.
you probably need to have a reducer first. let's say selectState
and then you need an action. here we name it changeSelectState
now, we can use connect from react-redux on the container component
and pass this method down to that presentational component. that's it.
So, the flow you can do is
add a reducer for storing data
add an action for changing the data
import that data and action via connect into container component
pass them down to presentational component
click and change the value via that action

Categories

Resources