not getting the value from outside render function - reactjs

i am new to react. please help me.
i am trying the get a value of data outside render.
data.map(
<button onClick = { () => { console.log (data)}}></button>
)
i am getting the value of data here. but
handleClick = () => {
console.log (data) /// not getting the value
}
<button onClick = { this.handleClick}></button>
if i try this.hadleClick , then i am not getting any value. why . thanks,

It's because you are not passing the value to your handleClick function. A couple options:
Bind the function with the params in your onClick:
data.map(
<button onClick = { this.handleClick.bind(this, data) }></button>
)
Pass an anonymous function to your click handler:
data.map(
<button onClick = { () => this.handleClick(data) }></button>
)
And you'll need to update your handleClick function to accept data as a param:
handleClick = data => {
console.log(data);
}

You should be passing the data you want to print to the function like below:
<button onClick = { () => this.handleClick(data) }></button>
(and your handler function should accept it as well)
handleClick = (data) => console.log(data);

Related

How do you pass a callback function to a sibling component in React

How do you pass a callback function to a sibling component such that a button in one can trigger an action in the another? The following code is an example of an attempt I made that ended up infinitely resetting the state in Index.js
import React, {useState} from "react"
const ComplexComponent = ({setCallbackFunction}) => {
setCallbackFunction(() => console.log("hello world"))
return <div/>
}
const Button = ({onClick}) => {
return (
<button onClick={onClick}>
Submit
</button>
)
}
export default function Index() {
const [callbackFunction, setCallbackFunction] = useState(() => {})
// EXPECTED: callbackFunction should log "hello world" after clicking Button
// ACTUAL: state is reset infinitely
return (
<>
<ComplexComponent setCallbackFunction={setCallbackFunction} />
<Button onClick={callbackFunction}/>
</>
)
}
In this case function is getting executed as soon as you initialize. example below, the function is not returning anything. its just printing initial immediately. Since its not returning anything, undefined will be set to callbackFunction variable.
const [callbackFunction, setCallbackFunction] = React.useState(() =>
console.log('initial')
);
solution:
wrap the function with another function. so that, the outer function returns inner function instead of undefined
const [callbackFunction, setCallbackFunction] = React.useState(
() => () => console.log('initial')
);
now you can reset call back function, again with a wrapper function. without the wrapper same thing here as before. function will get executed immediately and print hello world
const ComplexComponent = ({ setCallbackFunction }) => {
setCallbackFunction(() => () => console.log('hello world'));
return <div />;
};
to avoid different component render error consider useEffect.
const ComplexComponent = ({ setCallbackFunction }) => {
React.useEffect(() => {
setCallbackFunction(() => () => console.log('hello world'));
}, []);
return <div />;
};

React state not correct when function called via addEventListener

I have a React component that uses state to manage a changed variable if a form input is updated.
Assuming I've made some updates to the form, the issue I'm having is if I dispatch a click event to the onCancel function using addEventListener the value of changed is not correct but if I call onCancel from the JSX the value is correct.
Any ideas?
const Edit = (props) => {
let [changed, setChanged] = useState(false);
// Fired when a form value is updated
const onChange = (e) => {
setChanged("true");
};
// Close modal
const onCancel = () => {
console.log(changed); // This will be false when triggered from addEventListener
};
useEffect(() => {
let form = document.querySelector(".oda-edit-form");
// Close Window on click outside
form.addEventListener("click", function () {
onCancel();
});
}, []);
return (
<div>
<input type="text" onChange={(e) => onChange(e)} />
<button onClick={onCancel}>Close</button>
</div>
);
};
You need to re render your component as soon your state changes to run the onCancel() funtion.
let form = document.querySelector(".oda-edit-form");
// Close Window on click outside
form.addEventListener("click", function () {
onCancel();
});
}, [changed]); // < ----- add dependancy
Removed the addEventListener and added an onClick directly to the JSX with a custom method.
const Edit = (props) => {
let [changed, setChanged] = useState(false);
// Fired when a form value is updated
const onChange = (e) => {
setChanged("true");
};
// Close modal
const onCancel = () => {
console.log(changed); // This will be false when triggered from addEventListener
};
const onClickOutside = (e) => {
let element = e.target.querySelector('.wide-card');
let isClickInside = element.contains(event.target);
// // Close Modal
if (!isClickInside) {
onCancel();
}
};
return (
<div onClick-{(e)=>onClickOutside(e)}>
<input type="text" onChange={(e) => onChange(e)} />
<button onClick={onCancel}>Close</button>
</div>
);
};

Cannot get updated state value inside event handler

I'm trying to get increased item inside updateItem handler whenever I click on window. It appears updated on the screen, but what is strange is that only initial value 0 appears inside updateItem event handler.
const TodoApp = () => {
const [item, setItem] = React.useState(0);
const updateItem = () => {
console.log(item); // always prints 0
setItem((val) => val + 1);
};
React.useEffect(() => {
window.addEventListener('click', updateItem);
return () => {
window.removeEventListener('click', updateItem);
};
}, []);
return (
<div>
<h2>{item}</h2>
</div>
)
}
What is the main problem?
Thank you.
I found the reason on my side.
Any value being used inside event handler gets its value from the closure where it was defined. So it only appears as its initial value.
The solution is to subscribe the event handler again whenever the state is changed,
like this:
React.useEffect(() => {
window.addEventListener('click', updateItem);
return () => {
window.removeEventListener('click', updateItem);
};
}, [item]);
There's also another way, using ref because it always keeps the latest value.

State property updated value cannot be accessed in onClick function

I'm using React Hooks. I set the state property questions after an axios fetch call. Now when I click a button, in its function questions state is still empty
const [questions, setQuestions] = useState([]);
const [customComponent, setCustomComponent] = useState(<div />);
useEffect(() => {
axios.get("urlhere").then(res => {
console.log(12, res.data);
setQuestions(res.data);
res.data.map(q => {
if (q.qualifyingQuestionId == 1) {
setCustomComponent(renderSteps(q, q.qualifyingQuestionId));
}
});
});
}, []);
const handleNext = i => {
console.log(32, questions); //questions is still an empty array here
};
const renderSteps = (step, i) => {
switch (step.controlTypeName) {
case "textbox":
return (
<div key={i}>
<input type="text" placeholder={step.content} />
<button onClick={() => handleNext(i)}>Next</button>
</div>
);
}
};
return <>{customComponent}</>;
Do I need to use reducers here and put the custom component in another "file"?
setQuestions does not update state immediately, you should use the prevState instead to access the new value.
Here's a sandbox to match your codes with some explanation on why it was empty > https://codesandbox.io/s/axios-useeffect-kdgnw
You can also read about it here: Why calling react setState method doesn't mutate the state immediately?
Finally I have my own solution
I passed down the data from the fetch function to another component as props
useEffect(() => {
axios.get('url')
.then((data) => {
setCustomComponent(<Questions questions={data} />)
})
}, [])

How to provide props.history push as a function's argument

I have the following function which I use in two components:
export const removeItem = (id, cb) => {
try {
const remove = async () => {
await axios.delete(`http://localhost:9000/news/${id}`);
cb();
};
remove();
} catch (e) {
console.log(e)
}
}
Im my NewsItemPage component I want to provide props.history.push('/news') as the second argument, but this code would not work:
<button onClick={() => {removeItem(someId, props.history.push('/news')) }}>remove</button>
Any help much appreciated.
You have to put a function around it to be able to use as callback.
like this <button onClick={() => {removeItem(someId, () => {props.history.push('/news')}) }}>remove</button>

Resources